mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
async await desugaring and tests
This commit is contained in:
parent
589446e19c
commit
cf844b547d
@ -2131,5 +2131,10 @@ register_diagnostics! {
|
|||||||
E0657, // `impl Trait` can only capture lifetimes bound at the fn level
|
E0657, // `impl Trait` can only capture lifetimes bound at the fn level
|
||||||
E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
|
E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
|
||||||
E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
|
E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
|
||||||
E0697, // closures cannot be static
|
|
||||||
|
E0906, // closures cannot be static
|
||||||
|
|
||||||
|
E0703, // multiple different lifetimes used in arguments of `async fn`
|
||||||
|
E0704, // multiple elided lifetimes used in arguments of `async fn`
|
||||||
|
E0705, // `async` non-`move` closures with arguments are not currently supported
|
||||||
}
|
}
|
||||||
|
@ -449,7 +449,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate_hir_id_counter<T: Debug>(&mut self, owner: NodeId, debug: &T) {
|
fn allocate_hir_id_counter<T: Debug>(&mut self, owner: NodeId, debug: &T) -> LoweredNodeId {
|
||||||
if self.item_local_id_counters.insert(owner, 0).is_some() {
|
if self.item_local_id_counters.insert(owner, 0).is_some() {
|
||||||
bug!(
|
bug!(
|
||||||
"Tried to allocate item_local_id_counter for {:?} twice",
|
"Tried to allocate item_local_id_counter for {:?} twice",
|
||||||
@ -457,7 +457,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Always allocate the first HirId for the owner itself
|
// Always allocate the first HirId for the owner itself
|
||||||
self.lower_node_id_with_owner(owner, owner);
|
self.lower_node_id_with_owner(owner, owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_node_id_generic<F>(&mut self, ast_node_id: NodeId, alloc_hir_id: F) -> LoweredNodeId
|
fn lower_node_id_generic<F>(&mut self, ast_node_id: NodeId, alloc_hir_id: F) -> LoweredNodeId
|
||||||
@ -501,7 +501,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
{
|
{
|
||||||
let counter = self.item_local_id_counters
|
let counter = self.item_local_id_counters
|
||||||
.insert(owner, HIR_ID_COUNTER_LOCKED)
|
.insert(owner, HIR_ID_COUNTER_LOCKED)
|
||||||
.unwrap();
|
.unwrap_or_else(|| panic!("No item_local_id_counters entry for {:?}", owner));
|
||||||
let def_index = self.resolver.definitions().opt_def_index(owner).unwrap();
|
let def_index = self.resolver.definitions().opt_def_index(owner).unwrap();
|
||||||
self.current_hir_id_owner.push((def_index, counter));
|
self.current_hir_id_owner.push((def_index, counter));
|
||||||
let ret = f(self);
|
let ret = f(self);
|
||||||
@ -840,6 +840,46 @@ impl<'a> LoweringContext<'a> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_async_expr(
|
||||||
|
&mut self,
|
||||||
|
capture_clause: CaptureBy,
|
||||||
|
closure_node_id: NodeId,
|
||||||
|
ret_ty: Option<&Ty>,
|
||||||
|
body: impl FnOnce(&mut LoweringContext) -> hir::Expr,
|
||||||
|
) -> hir::Expr_ {
|
||||||
|
let prev_is_generator = mem::replace(&mut self.is_generator, true);
|
||||||
|
let body_expr = body(self);
|
||||||
|
let span = body_expr.span;
|
||||||
|
let output = match ret_ty {
|
||||||
|
Some(ty) => FunctionRetTy::Ty(P(ty.clone())),
|
||||||
|
None => FunctionRetTy::Default(span),
|
||||||
|
};
|
||||||
|
let decl = FnDecl {
|
||||||
|
inputs: vec![],
|
||||||
|
output,
|
||||||
|
variadic: false
|
||||||
|
};
|
||||||
|
let body_id = self.record_body(body_expr, Some(&decl));
|
||||||
|
self.is_generator = prev_is_generator;
|
||||||
|
|
||||||
|
let capture_clause = self.lower_capture_clause(capture_clause);
|
||||||
|
let closure_hir_id = self.lower_node_id(closure_node_id).hir_id;
|
||||||
|
let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, false);
|
||||||
|
let generator = hir::Expr {
|
||||||
|
id: closure_node_id,
|
||||||
|
hir_id: closure_hir_id,
|
||||||
|
node: hir::ExprClosure(capture_clause, decl, body_id, span,
|
||||||
|
Some(hir::GeneratorMovability::Static)),
|
||||||
|
span,
|
||||||
|
attrs: ThinVec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let unstable_span = self.allow_internal_unstable(CompilerDesugaringKind::Async, span);
|
||||||
|
let gen_future = self.expr_std_path(
|
||||||
|
unstable_span, &["raw", "future_from_generator"], ThinVec::new());
|
||||||
|
hir::ExprCall(P(gen_future), hir_vec![generator])
|
||||||
|
}
|
||||||
|
|
||||||
fn lower_body<F>(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId
|
fn lower_body<F>(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut LoweringContext) -> hir::Expr,
|
F: FnOnce(&mut LoweringContext) -> hir::Expr,
|
||||||
@ -1067,7 +1107,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
),
|
),
|
||||||
unsafety: this.lower_unsafety(f.unsafety),
|
unsafety: this.lower_unsafety(f.unsafety),
|
||||||
abi: f.abi,
|
abi: f.abi,
|
||||||
decl: this.lower_fn_decl(&f.decl, None, false),
|
decl: this.lower_fn_decl(&f.decl, None, false, false),
|
||||||
arg_names: this.lower_fn_args_to_names(&f.decl),
|
arg_names: this.lower_fn_args_to_names(&f.decl),
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
@ -1132,92 +1172,10 @@ impl<'a> LoweringContext<'a> {
|
|||||||
let span = t.span;
|
let span = t.span;
|
||||||
match itctx {
|
match itctx {
|
||||||
ImplTraitContext::Existential(fn_def_id) => {
|
ImplTraitContext::Existential(fn_def_id) => {
|
||||||
|
// Set the name to `impl Bound1 + Bound2`
|
||||||
// We need to manually repeat the code of `next_id` because the lowering
|
let exist_ty_name = Symbol::intern(&pprust::ty_to_string(t));
|
||||||
// needs to happen while the owner_id is pointing to the item itself,
|
self.lower_existential_impl_trait(
|
||||||
// because items are their own owners
|
span, fn_def_id, exist_ty_name, |this| this.lower_bounds(bounds, itctx))
|
||||||
let exist_ty_node_id = self.sess.next_node_id();
|
|
||||||
|
|
||||||
// Make sure we know that some funky desugaring has been going on here.
|
|
||||||
// This is a first: there is code in other places like for loop
|
|
||||||
// desugaring that explicitly states that we don't want to track that.
|
|
||||||
// Not tracking it makes lints in rustc and clippy very fragile as
|
|
||||||
// frequently opened issues show.
|
|
||||||
let exist_ty_span = self.allow_internal_unstable(
|
|
||||||
CompilerDesugaringKind::ExistentialReturnType,
|
|
||||||
t.span,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Pull a new definition from the ether
|
|
||||||
let exist_ty_def_index = self
|
|
||||||
.resolver
|
|
||||||
.definitions()
|
|
||||||
.create_def_with_parent(
|
|
||||||
fn_def_id.index,
|
|
||||||
exist_ty_node_id,
|
|
||||||
DefPathData::ExistentialImplTrait,
|
|
||||||
DefIndexAddressSpace::High,
|
|
||||||
Mark::root(),
|
|
||||||
exist_ty_span,
|
|
||||||
);
|
|
||||||
|
|
||||||
// the `t` is just for printing debug messages
|
|
||||||
self.allocate_hir_id_counter(exist_ty_node_id, t);
|
|
||||||
|
|
||||||
let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, |lctx| {
|
|
||||||
lctx.lower_param_bounds(bounds, itctx)
|
|
||||||
});
|
|
||||||
|
|
||||||
let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
|
|
||||||
exist_ty_node_id,
|
|
||||||
exist_ty_def_index,
|
|
||||||
&hir_bounds,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.with_hir_id_owner(exist_ty_node_id, |lctx| {
|
|
||||||
let exist_ty_item_kind = hir::ItemExistential(hir::ExistTy {
|
|
||||||
generics: hir::Generics {
|
|
||||||
params: lifetime_defs,
|
|
||||||
where_clause: hir::WhereClause {
|
|
||||||
id: lctx.next_id().node_id,
|
|
||||||
predicates: Vec::new().into(),
|
|
||||||
},
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
bounds: hir_bounds,
|
|
||||||
impl_trait_fn: Some(fn_def_id),
|
|
||||||
});
|
|
||||||
let exist_ty_id = lctx.lower_node_id(exist_ty_node_id);
|
|
||||||
// Generate an `existential type Foo: Trait;` declaration
|
|
||||||
trace!("creating existential type with id {:#?}", exist_ty_id);
|
|
||||||
// Set the name to `impl Bound1 + Bound2`
|
|
||||||
let exist_ty_name = Symbol::intern(&pprust::ty_to_string(t));
|
|
||||||
|
|
||||||
trace!("exist ty def index: {:#?}", exist_ty_def_index);
|
|
||||||
let exist_ty_item = hir::Item {
|
|
||||||
id: exist_ty_id.node_id,
|
|
||||||
hir_id: exist_ty_id.hir_id,
|
|
||||||
name: exist_ty_name,
|
|
||||||
attrs: Default::default(),
|
|
||||||
node: exist_ty_item_kind,
|
|
||||||
vis: hir::Visibility::Inherited,
|
|
||||||
span: exist_ty_span,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Insert the item into the global list. This usually happens
|
|
||||||
// automatically for all AST items. But this existential type item
|
|
||||||
// does not actually exist in the AST.
|
|
||||||
lctx.items.insert(exist_ty_id.node_id, exist_ty_item);
|
|
||||||
|
|
||||||
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`
|
|
||||||
hir::TyImplTraitExistential(
|
|
||||||
hir::ItemId {
|
|
||||||
id: exist_ty_id.node_id
|
|
||||||
},
|
|
||||||
DefId::local(exist_ty_def_index),
|
|
||||||
lifetimes,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
ImplTraitContext::Universal(def_id) => {
|
ImplTraitContext::Universal(def_id) => {
|
||||||
let def_node_id = self.next_id().node_id;
|
let def_node_id = self.next_id().node_id;
|
||||||
@ -1281,6 +1239,95 @@ impl<'a> LoweringContext<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lower_existential_impl_trait(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
fn_def_id: DefId,
|
||||||
|
exist_ty_name: Name,
|
||||||
|
lower_bounds: impl FnOnce(&mut LoweringContext) -> hir::TyParamBounds,
|
||||||
|
) -> hir::Ty_ {
|
||||||
|
// We need to manually repeat the code of `next_id` because the lowering
|
||||||
|
// needs to happen while the owner_id is pointing to the item itself,
|
||||||
|
// because items are their own owners
|
||||||
|
let exist_ty_node_id = self.sess.next_node_id();
|
||||||
|
|
||||||
|
// Make sure we know that some funky desugaring has been going on here.
|
||||||
|
// This is a first: there is code in other places like for loop
|
||||||
|
// desugaring that explicitly states that we don't want to track that.
|
||||||
|
// Not tracking it makes lints in rustc and clippy very fragile as
|
||||||
|
// frequently opened issues show.
|
||||||
|
let exist_ty_span = self.allow_internal_unstable(
|
||||||
|
CompilerDesugaringKind::ExistentialReturnType,
|
||||||
|
span,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Pull a new definition from the ether
|
||||||
|
let exist_ty_def_index = self
|
||||||
|
.resolver
|
||||||
|
.definitions()
|
||||||
|
.create_def_with_parent(
|
||||||
|
fn_def_id.index,
|
||||||
|
exist_ty_node_id,
|
||||||
|
DefPathData::ExistentialImplTrait,
|
||||||
|
DefIndexAddressSpace::High,
|
||||||
|
Mark::root(),
|
||||||
|
exist_ty_span,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.allocate_hir_id_counter(exist_ty_node_id, &"existential impl trait");
|
||||||
|
|
||||||
|
let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, lower_bounds);
|
||||||
|
|
||||||
|
let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
|
||||||
|
exist_ty_node_id,
|
||||||
|
exist_ty_def_index,
|
||||||
|
&hir_bounds,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.with_hir_id_owner(exist_ty_node_id, |lctx| {
|
||||||
|
let exist_ty_item_kind = hir::ItemExistential(hir::ExistTy {
|
||||||
|
generics: hir::Generics {
|
||||||
|
params: lifetime_defs,
|
||||||
|
where_clause: hir::WhereClause {
|
||||||
|
id: lctx.next_id().node_id,
|
||||||
|
predicates: Vec::new().into(),
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
bounds: hir_bounds,
|
||||||
|
impl_trait_fn: Some(fn_def_id),
|
||||||
|
});
|
||||||
|
let exist_ty_id = lctx.lower_node_id(exist_ty_node_id);
|
||||||
|
// Generate an `existential type Foo: Trait;` declaration
|
||||||
|
trace!("creating existential type with id {:#?}", exist_ty_id);
|
||||||
|
|
||||||
|
trace!("exist ty def index: {:#?}", exist_ty_def_index);
|
||||||
|
let exist_ty_item = hir::Item {
|
||||||
|
id: exist_ty_id.node_id,
|
||||||
|
hir_id: exist_ty_id.hir_id,
|
||||||
|
name: exist_ty_name,
|
||||||
|
attrs: Default::default(),
|
||||||
|
node: exist_ty_item_kind,
|
||||||
|
vis: hir::Visibility::Inherited,
|
||||||
|
span: exist_ty_span,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Insert the item into the global list. This usually happens
|
||||||
|
// automatically for all AST items. But this existential type item
|
||||||
|
// does not actually exist in the AST.
|
||||||
|
lctx.items.insert(exist_ty_id.node_id, exist_ty_item);
|
||||||
|
|
||||||
|
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`
|
||||||
|
hir::TyImplTraitExistential(
|
||||||
|
hir::ItemId {
|
||||||
|
id: exist_ty_id.node_id
|
||||||
|
},
|
||||||
|
DefId::local(exist_ty_def_index),
|
||||||
|
lifetimes,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn lifetimes_from_impl_trait_bounds(
|
fn lifetimes_from_impl_trait_bounds(
|
||||||
&mut self,
|
&mut self,
|
||||||
exist_ty_id: NodeId,
|
exist_ty_id: NodeId,
|
||||||
@ -1829,31 +1876,40 @@ impl<'a> LoweringContext<'a> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lowers a function declaration.
|
||||||
|
//
|
||||||
|
// decl: the unlowered (ast) function declaration.
|
||||||
|
// fn_def_id: if `Some`, impl Trait arguments are lowered into generic parameters on the
|
||||||
|
// given DefId, otherwise impl Trait is disallowed. Must be `Some` if
|
||||||
|
// make_ret_async is true.
|
||||||
|
// impl_trait_return_allow: determines whether impl Trait can be used in return position.
|
||||||
|
// This guards against trait declarations and implementations where impl Trait is
|
||||||
|
// disallowed.
|
||||||
|
// make_ret_async: if enabled, converts `-> T` into `-> impl Future<Output = T>` in the
|
||||||
|
// return type. This is used for `async fn` declarations.
|
||||||
fn lower_fn_decl(
|
fn lower_fn_decl(
|
||||||
&mut self,
|
&mut self,
|
||||||
decl: &FnDecl,
|
decl: &FnDecl,
|
||||||
fn_def_id: Option<DefId>,
|
fn_def_id: Option<DefId>,
|
||||||
impl_trait_return_allow: bool,
|
impl_trait_return_allow: bool,
|
||||||
|
make_ret_async: bool,
|
||||||
) -> P<hir::FnDecl> {
|
) -> P<hir::FnDecl> {
|
||||||
// NOTE: The two last parameters here have to do with impl Trait. If fn_def_id is Some,
|
let inputs = decl.inputs
|
||||||
// then impl Trait arguments are lowered into generic parameters on the given
|
.iter()
|
||||||
// fn_def_id, otherwise impl Trait is disallowed. (for now)
|
.map(|arg| {
|
||||||
//
|
if let Some(def_id) = fn_def_id {
|
||||||
// Furthermore, if impl_trait_return_allow is true, then impl Trait may be used in
|
self.lower_ty(&arg.ty, ImplTraitContext::Universal(def_id))
|
||||||
// return positions as well. This guards against trait declarations and their impls
|
} else {
|
||||||
// where impl Trait is disallowed. (again for now)
|
self.lower_ty(&arg.ty, ImplTraitContext::Disallowed)
|
||||||
P(hir::FnDecl {
|
}
|
||||||
inputs: decl.inputs
|
})
|
||||||
.iter()
|
.collect::<HirVec<_>>();
|
||||||
.map(|arg| {
|
|
||||||
if let Some(def_id) = fn_def_id {
|
let output = if make_ret_async {
|
||||||
self.lower_ty(&arg.ty, ImplTraitContext::Universal(def_id))
|
self.lower_async_fn_ret_ty(
|
||||||
} else {
|
&inputs, &decl.output, fn_def_id.expect("make_ret_async but no fn_def_id"))
|
||||||
self.lower_ty(&arg.ty, ImplTraitContext::Disallowed)
|
} else {
|
||||||
}
|
match decl.output {
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
output: match decl.output {
|
|
||||||
FunctionRetTy::Ty(ref ty) => match fn_def_id {
|
FunctionRetTy::Ty(ref ty) => match fn_def_id {
|
||||||
Some(def_id) if impl_trait_return_allow => {
|
Some(def_id) if impl_trait_return_allow => {
|
||||||
hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(def_id)))
|
hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(def_id)))
|
||||||
@ -1861,7 +1917,12 @@ impl<'a> LoweringContext<'a> {
|
|||||||
_ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
|
_ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
|
||||||
},
|
},
|
||||||
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
|
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
|
||||||
},
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
P(hir::FnDecl {
|
||||||
|
inputs,
|
||||||
|
output,
|
||||||
variadic: decl.variadic,
|
variadic: decl.variadic,
|
||||||
has_implicit_self: decl.inputs.get(0).map_or(false, |arg| match arg.ty.node {
|
has_implicit_self: decl.inputs.get(0).map_or(false, |arg| match arg.ty.node {
|
||||||
TyKind::ImplicitSelf => true,
|
TyKind::ImplicitSelf => true,
|
||||||
@ -1871,6 +1932,243 @@ impl<'a> LoweringContext<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transform `-> T` into `-> impl Future<Output = T>` for `async fn`
|
||||||
|
//
|
||||||
|
// fn_span: the span of the async function declaration. Used for error reporting.
|
||||||
|
// inputs: lowered types of arguments to the function. Used to collect lifetimes.
|
||||||
|
// output: unlowered output type (`T` in `-> T`)
|
||||||
|
// fn_def_id: DefId of the parent function. Used to create child impl trait definition.
|
||||||
|
fn lower_async_fn_ret_ty(
|
||||||
|
&mut self,
|
||||||
|
inputs: &[P<hir::Ty>],
|
||||||
|
output: &FunctionRetTy,
|
||||||
|
fn_def_id: DefId,
|
||||||
|
) -> hir::FunctionRetTy {
|
||||||
|
// Get lifetimes used in the input arguments to the function. Our output type must also
|
||||||
|
// have the same lifetime. FIXME(cramertj) multiple different lifetimes are not allowed
|
||||||
|
// because `impl Trait + 'a + 'b` doesn't allow for capture `'a` and `'b` where neither
|
||||||
|
// is a subset of the other. We really want some new lifetime that is a subset of all input
|
||||||
|
// lifetimes, but that doesn't exist at the moment.
|
||||||
|
|
||||||
|
struct AsyncFnLifetimeCollector<'r, 'a: 'r> {
|
||||||
|
context: &'r mut LoweringContext<'a>,
|
||||||
|
// Lifetimes bound by HRTB
|
||||||
|
currently_bound_lifetimes: Vec<hir::LifetimeName>,
|
||||||
|
// Whether to count elided lifetimes.
|
||||||
|
// Disabled inside of `Fn` or `fn` syntax.
|
||||||
|
collect_elided_lifetimes: bool,
|
||||||
|
// The lifetime found.
|
||||||
|
// Multiple different or elided lifetimes cannot appear in async fn for now.
|
||||||
|
output_lifetime: Option<(hir::LifetimeName, Span)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for AsyncFnLifetimeCollector<'r, 'a> {
|
||||||
|
fn nested_visit_map<'this>(
|
||||||
|
&'this mut self,
|
||||||
|
) -> hir::intravisit::NestedVisitorMap<'this, 'v> {
|
||||||
|
hir::intravisit::NestedVisitorMap::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_path_parameters(&mut self, span: Span, parameters: &'v hir::PathParameters) {
|
||||||
|
// Don't collect elided lifetimes used inside of `Fn()` syntax.
|
||||||
|
if parameters.parenthesized {
|
||||||
|
let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
|
||||||
|
self.collect_elided_lifetimes = false;
|
||||||
|
hir::intravisit::walk_path_parameters(self, span, parameters);
|
||||||
|
self.collect_elided_lifetimes = old_collect_elided_lifetimes;
|
||||||
|
} else {
|
||||||
|
hir::intravisit::walk_path_parameters(self, span, parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_ty(&mut self, t: &'v hir::Ty) {
|
||||||
|
// Don't collect elided lifetimes used inside of `fn()` syntax
|
||||||
|
if let &hir::Ty_::TyBareFn(_) = &t.node {
|
||||||
|
let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
|
||||||
|
self.collect_elided_lifetimes = false;
|
||||||
|
|
||||||
|
// Record the "stack height" of `for<'a>` lifetime bindings
|
||||||
|
// to be able to later fully undo their introduction.
|
||||||
|
let old_len = self.currently_bound_lifetimes.len();
|
||||||
|
hir::intravisit::walk_ty(self, t);
|
||||||
|
self.currently_bound_lifetimes.truncate(old_len);
|
||||||
|
|
||||||
|
self.collect_elided_lifetimes = old_collect_elided_lifetimes;
|
||||||
|
} else {
|
||||||
|
hir::intravisit::walk_ty(self, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_poly_trait_ref(
|
||||||
|
&mut self,
|
||||||
|
trait_ref: &'v hir::PolyTraitRef,
|
||||||
|
modifier: hir::TraitBoundModifier,
|
||||||
|
) {
|
||||||
|
// Record the "stack height" of `for<'a>` lifetime bindings
|
||||||
|
// to be able to later fully undo their introduction.
|
||||||
|
let old_len = self.currently_bound_lifetimes.len();
|
||||||
|
hir::intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
|
||||||
|
self.currently_bound_lifetimes.truncate(old_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_generic_param(&mut self, param: &'v hir::GenericParam) {
|
||||||
|
// Record the introduction of 'a in `for<'a> ...`
|
||||||
|
if let hir::GenericParam::Lifetime(ref lt_def) = *param {
|
||||||
|
// Introduce lifetimes one at a time so that we can handle
|
||||||
|
// cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`
|
||||||
|
self.currently_bound_lifetimes.push(lt_def.lifetime.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::intravisit::walk_generic_param(self, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
|
||||||
|
let name = match lifetime.name {
|
||||||
|
hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
|
||||||
|
if self.collect_elided_lifetimes {
|
||||||
|
// Use `'_` for both implicit and underscore lifetimes in
|
||||||
|
// `abstract type Foo<'_>: SomeTrait<'_>;`
|
||||||
|
hir::LifetimeName::Underscore
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name @ hir::LifetimeName::Fresh(_) => name,
|
||||||
|
name @ hir::LifetimeName::Name(_) => name,
|
||||||
|
hir::LifetimeName::Static => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !self.currently_bound_lifetimes.contains(&name) {
|
||||||
|
if let Some((current_lt_name, current_lt_span)) = self.output_lifetime {
|
||||||
|
// We don't currently have a reliable way to desugar `async fn` with
|
||||||
|
// multiple potentially unrelated input lifetimes into
|
||||||
|
// `-> impl Trait + 'lt`, so we report an error in this case.
|
||||||
|
if current_lt_name != name {
|
||||||
|
struct_span_err!(
|
||||||
|
self.context.sess,
|
||||||
|
current_lt_span.between(lifetime.span),
|
||||||
|
E0703,
|
||||||
|
"multiple different lifetimes used in arguments of `async fn`",
|
||||||
|
)
|
||||||
|
.span_label(current_lt_span, "first lifetime here")
|
||||||
|
.span_label(lifetime.span, "different lifetime here")
|
||||||
|
.help("`async fn` can only accept borrowed values \
|
||||||
|
identical lifetimes")
|
||||||
|
.emit()
|
||||||
|
} else if current_lt_name.is_elided() && name.is_elided() {
|
||||||
|
struct_span_err!(
|
||||||
|
self.context.sess,
|
||||||
|
current_lt_span.between(lifetime.span),
|
||||||
|
E0704,
|
||||||
|
"multiple elided lifetimes used in arguments of `async fn`",
|
||||||
|
)
|
||||||
|
.span_label(current_lt_span, "first lifetime here")
|
||||||
|
.span_label(lifetime.span, "different lifetime here")
|
||||||
|
.help("consider giving these arguments named lifetimes")
|
||||||
|
.emit()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.output_lifetime = Some((name, lifetime.span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let bound_lifetime = {
|
||||||
|
let mut lifetime_collector = AsyncFnLifetimeCollector {
|
||||||
|
context: self,
|
||||||
|
currently_bound_lifetimes: Vec::new(),
|
||||||
|
collect_elided_lifetimes: true,
|
||||||
|
output_lifetime: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
for arg in inputs {
|
||||||
|
hir::intravisit::walk_ty(&mut lifetime_collector, arg);
|
||||||
|
}
|
||||||
|
lifetime_collector.output_lifetime
|
||||||
|
};
|
||||||
|
|
||||||
|
let output_ty_name_owned;
|
||||||
|
let (output_ty_name, span) = match output {
|
||||||
|
FunctionRetTy::Ty(ty) => {
|
||||||
|
output_ty_name_owned = pprust::ty_to_string(ty);
|
||||||
|
(&*output_ty_name_owned, ty.span)
|
||||||
|
},
|
||||||
|
FunctionRetTy::Default(span) => ("()", *span),
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME(cramertj) add lifetimes (see FIXME below) to the name
|
||||||
|
let exist_ty_name = Symbol::intern(&format!("impl Future<Output = {}>", output_ty_name));
|
||||||
|
let impl_trait_ty = self.lower_existential_impl_trait(
|
||||||
|
span, fn_def_id, exist_ty_name, |this| {
|
||||||
|
let output_ty = match output {
|
||||||
|
FunctionRetTy::Ty(ty) =>
|
||||||
|
this.lower_ty(ty, ImplTraitContext::Existential(fn_def_id)),
|
||||||
|
FunctionRetTy::Default(span) => {
|
||||||
|
let LoweredNodeId { node_id, hir_id } = this.next_id();
|
||||||
|
P(hir::Ty {
|
||||||
|
id: node_id,
|
||||||
|
hir_id: hir_id,
|
||||||
|
node: hir::TyTup(hir_vec![]),
|
||||||
|
span: *span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let hir::Path { def, segments, .. } = this.std_path(span, &["future", "Future"], false);
|
||||||
|
let future_path = hir::Path {
|
||||||
|
segments: segments.map_slice(|mut v| {
|
||||||
|
v.last_mut().unwrap().parameters = Some(P(hir::PathParameters {
|
||||||
|
lifetimes: hir_vec![],
|
||||||
|
types: hir_vec![],
|
||||||
|
bindings: hir_vec![hir::TypeBinding {
|
||||||
|
name: Symbol::intern(FN_OUTPUT_NAME),
|
||||||
|
ty: output_ty,
|
||||||
|
id: this.next_id().node_id,
|
||||||
|
span,
|
||||||
|
}],
|
||||||
|
parenthesized: false,
|
||||||
|
}));
|
||||||
|
v
|
||||||
|
}),
|
||||||
|
def, span
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME(cramertj) collect input lifetimes to function and add them to
|
||||||
|
// the output `impl Trait` type here.
|
||||||
|
let mut bounds = vec![
|
||||||
|
hir::TyParamBound::TraitTyParamBound(
|
||||||
|
hir::PolyTraitRef {
|
||||||
|
trait_ref: hir::TraitRef {
|
||||||
|
path: future_path,
|
||||||
|
ref_id: this.next_id().node_id,
|
||||||
|
},
|
||||||
|
bound_generic_params: hir_vec![],
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
hir::TraitBoundModifier::None
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
if let Some((name, span)) = bound_lifetime {
|
||||||
|
bounds.push(hir::RegionTyParamBound(
|
||||||
|
hir::Lifetime { id: this.next_id().node_id, name, span }));
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::HirVec::from(bounds)
|
||||||
|
});
|
||||||
|
|
||||||
|
let LoweredNodeId { node_id, hir_id } = self.next_id();
|
||||||
|
let impl_trait_ty = P(hir::Ty {
|
||||||
|
id: node_id,
|
||||||
|
node: impl_trait_ty,
|
||||||
|
span,
|
||||||
|
hir_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
hir::FunctionRetTy::Return(impl_trait_ty)
|
||||||
|
}
|
||||||
|
|
||||||
fn lower_param_bound(
|
fn lower_param_bound(
|
||||||
&mut self,
|
&mut self,
|
||||||
tpb: &GenericBound,
|
tpb: &GenericBound,
|
||||||
@ -2286,16 +2584,32 @@ impl<'a> LoweringContext<'a> {
|
|||||||
}
|
}
|
||||||
ItemKind::Fn(ref decl, header, ref generics, ref body) => {
|
ItemKind::Fn(ref decl, header, ref generics, ref body) => {
|
||||||
let fn_def_id = self.resolver.definitions().local_def_id(id);
|
let fn_def_id = self.resolver.definitions().local_def_id(id);
|
||||||
|
|
||||||
self.with_new_scopes(|this| {
|
self.with_new_scopes(|this| {
|
||||||
|
// Note: we can use non-async decl here because lower_body
|
||||||
|
// only cares about the input argument patterns,
|
||||||
|
// not the return types.
|
||||||
let body_id = this.lower_body(Some(decl), |this| {
|
let body_id = this.lower_body(Some(decl), |this| {
|
||||||
let body = this.lower_block(body, false);
|
if let IsAsync::Async(async_node_id) = header.asyncness {
|
||||||
this.expr_block(body, ThinVec::new())
|
let async_expr = this.make_async_expr(
|
||||||
|
CaptureBy::Value, async_node_id, None,
|
||||||
|
|this| {
|
||||||
|
let body = this.lower_block(body, false);
|
||||||
|
this.expr_block(body, ThinVec::new())
|
||||||
|
});
|
||||||
|
this.expr(body.span, async_expr, ThinVec::new())
|
||||||
|
} else {
|
||||||
|
let body = this.lower_block(body, false);
|
||||||
|
this.expr_block(body, ThinVec::new())
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let (generics, fn_decl) = this.add_in_band_defs(
|
let (generics, fn_decl) = this.add_in_band_defs(
|
||||||
generics,
|
generics,
|
||||||
fn_def_id,
|
fn_def_id,
|
||||||
AnonymousLifetimeMode::PassThrough,
|
AnonymousLifetimeMode::PassThrough,
|
||||||
|this| this.lower_fn_decl(decl, Some(fn_def_id), true),
|
|this| this.lower_fn_decl(
|
||||||
|
decl, Some(fn_def_id), true, header.asyncness.is_async())
|
||||||
);
|
);
|
||||||
|
|
||||||
hir::ItemFn(
|
hir::ItemFn(
|
||||||
@ -2863,7 +3177,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
|this| {
|
|this| {
|
||||||
(
|
(
|
||||||
// Disallow impl Trait in foreign items
|
// Disallow impl Trait in foreign items
|
||||||
this.lower_fn_decl(fdec, None, false),
|
this.lower_fn_decl(fdec, None, false, false),
|
||||||
this.lower_fn_args_to_names(fdec),
|
this.lower_fn_args_to_names(fdec),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -2890,7 +3204,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
) -> hir::MethodSig {
|
) -> hir::MethodSig {
|
||||||
hir::MethodSig {
|
hir::MethodSig {
|
||||||
header: self.lower_fn_header(sig.header),
|
header: self.lower_fn_header(sig.header),
|
||||||
decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow),
|
decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow, false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2926,7 +3240,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
|
|
||||||
fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync {
|
fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync {
|
||||||
match a {
|
match a {
|
||||||
IsAsync::Async => hir::IsAsync::Async,
|
IsAsync::Async(_) => hir::IsAsync::Async,
|
||||||
IsAsync::NotAsync => hir::IsAsync::NotAsync,
|
IsAsync::NotAsync => hir::IsAsync::NotAsync,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3218,46 +3532,101 @@ impl<'a> LoweringContext<'a> {
|
|||||||
arms.iter().map(|x| self.lower_arm(x)).collect(),
|
arms.iter().map(|x| self.lower_arm(x)).collect(),
|
||||||
hir::MatchSource::Normal,
|
hir::MatchSource::Normal,
|
||||||
),
|
),
|
||||||
ExprKind::Closure(capture_clause, movability, ref decl, ref body, fn_decl_span) => {
|
ExprKind::Async(capture_clause, closure_node_id, ref block) => {
|
||||||
|
self.make_async_expr(capture_clause, closure_node_id, None, |this| {
|
||||||
|
this.with_new_scopes(|this| {
|
||||||
|
let block = this.lower_block(block, false);
|
||||||
|
this.expr_block(block, ThinVec::new())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
ExprKind::Closure(
|
||||||
|
capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span) =>
|
||||||
|
{
|
||||||
self.with_new_scopes(|this| {
|
self.with_new_scopes(|this| {
|
||||||
let mut is_generator = false;
|
if let IsAsync::Async(async_closure_node_id) = asyncness {
|
||||||
let body_id = this.lower_body(Some(decl), |this| {
|
// FIXME(cramertj) allow `async` non-`move` closures with
|
||||||
let e = this.lower_expr(body);
|
if capture_clause == CaptureBy::Ref &&
|
||||||
is_generator = this.is_generator;
|
!decl.inputs.is_empty()
|
||||||
e
|
{
|
||||||
});
|
struct_span_err!(
|
||||||
let generator_option = if is_generator {
|
|
||||||
if !decl.inputs.is_empty() {
|
|
||||||
span_err!(
|
|
||||||
this.sess,
|
this.sess,
|
||||||
fn_decl_span,
|
fn_decl_span,
|
||||||
E0628,
|
E0705,
|
||||||
"generators cannot have explicit arguments"
|
"`async` non-`move` closures with arguments \
|
||||||
);
|
are not currently supported",
|
||||||
this.sess.abort_if_errors();
|
)
|
||||||
|
.help("consider using `let` statements to manually capture \
|
||||||
|
variables by reference before entering an \
|
||||||
|
`async move` closure")
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
Some(match movability {
|
|
||||||
Movability::Movable => hir::GeneratorMovability::Movable,
|
// Transform `async |x: u8| -> X { ... }` into
|
||||||
Movability::Static => hir::GeneratorMovability::Static,
|
// `|x: u8| future_from_generator(|| -> X { ... })`
|
||||||
})
|
let outer_decl = FnDecl {
|
||||||
|
inputs: decl.inputs.clone(),
|
||||||
|
output: FunctionRetTy::Default(fn_decl_span),
|
||||||
|
variadic: false,
|
||||||
|
};
|
||||||
|
let body_id = this.lower_body(Some(&outer_decl), |this| {
|
||||||
|
let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output {
|
||||||
|
Some(&**ty)
|
||||||
|
} else { None };
|
||||||
|
let async_body = this.make_async_expr(
|
||||||
|
capture_clause, async_closure_node_id, async_ret_ty,
|
||||||
|
|this| {
|
||||||
|
this.with_new_scopes(|this| this.lower_expr(body))
|
||||||
|
});
|
||||||
|
this.expr(fn_decl_span, async_body, ThinVec::new())
|
||||||
|
});
|
||||||
|
hir::ExprClosure(
|
||||||
|
this.lower_capture_clause(capture_clause),
|
||||||
|
this.lower_fn_decl(&outer_decl, None, false, false),
|
||||||
|
body_id,
|
||||||
|
fn_decl_span,
|
||||||
|
None,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
if movability == Movability::Static {
|
let mut is_generator = false;
|
||||||
span_err!(
|
let body_id = this.lower_body(Some(decl), |this| {
|
||||||
this.sess,
|
let e = this.lower_expr(body);
|
||||||
fn_decl_span,
|
is_generator = this.is_generator;
|
||||||
E0697,
|
e
|
||||||
"closures cannot be static"
|
});
|
||||||
);
|
let generator_option = if is_generator {
|
||||||
}
|
if !decl.inputs.is_empty() {
|
||||||
None
|
span_err!(
|
||||||
};
|
this.sess,
|
||||||
hir::ExprClosure(
|
fn_decl_span,
|
||||||
this.lower_capture_clause(capture_clause),
|
E0628,
|
||||||
this.lower_fn_decl(decl, None, false),
|
"generators cannot have explicit arguments"
|
||||||
body_id,
|
);
|
||||||
fn_decl_span,
|
this.sess.abort_if_errors();
|
||||||
generator_option,
|
}
|
||||||
)
|
Some(match movability {
|
||||||
|
Movability::Movable => hir::GeneratorMovability::Movable,
|
||||||
|
Movability::Static => hir::GeneratorMovability::Static,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if movability == Movability::Static {
|
||||||
|
span_err!(
|
||||||
|
this.sess,
|
||||||
|
fn_decl_span,
|
||||||
|
E0906,
|
||||||
|
"closures cannot be static"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
};
|
||||||
|
hir::ExprClosure(
|
||||||
|
this.lower_capture_clause(capture_clause),
|
||||||
|
this.lower_fn_decl(decl, None, false, false),
|
||||||
|
body_id,
|
||||||
|
fn_decl_span,
|
||||||
|
generator_option,
|
||||||
|
)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ExprKind::Block(ref blk, opt_label) => {
|
ExprKind::Block(ref blk, opt_label) => {
|
||||||
|
@ -99,6 +99,21 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||||||
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
|
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
|
||||||
return visit::walk_item(self, i);
|
return visit::walk_item(self, i);
|
||||||
}
|
}
|
||||||
|
ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, ..) => {
|
||||||
|
// For async functions, we need to create their inner defs inside of a
|
||||||
|
// closure to match their desugared representation.
|
||||||
|
let fn_def_data = DefPathData::ValueNs(i.ident.name.as_interned_str());
|
||||||
|
let fn_def = self.create_def(i.id, fn_def_data, ITEM_LIKE_SPACE, i.span);
|
||||||
|
return self.with_parent(fn_def, |this| {
|
||||||
|
let closure_def = this.create_def(async_node_id,
|
||||||
|
DefPathData::ClosureExpr,
|
||||||
|
REGULAR_SPACE,
|
||||||
|
i.span);
|
||||||
|
this.with_parent(closure_def, |this| {
|
||||||
|
visit::walk_item(this, i);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_interned_str()),
|
ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_interned_str()),
|
||||||
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
|
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
|
||||||
DefPathData::ValueNs(i.ident.name.as_interned_str()),
|
DefPathData::ValueNs(i.ident.name.as_interned_str()),
|
||||||
@ -227,15 +242,32 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||||||
|
|
||||||
match expr.node {
|
match expr.node {
|
||||||
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id),
|
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id),
|
||||||
ExprKind::Closure(..) => {
|
ExprKind::Closure(_, asyncness, ..) => {
|
||||||
let def = self.create_def(expr.id,
|
let closure_def = self.create_def(expr.id,
|
||||||
DefPathData::ClosureExpr,
|
DefPathData::ClosureExpr,
|
||||||
REGULAR_SPACE,
|
REGULAR_SPACE,
|
||||||
expr.span);
|
expr.span);
|
||||||
self.parent_def = Some(def);
|
self.parent_def = Some(closure_def);
|
||||||
|
|
||||||
|
// Async closures desugar to closures inside of closures, so
|
||||||
|
// we must create two defs.
|
||||||
|
if let IsAsync::Async(async_id) = asyncness {
|
||||||
|
let async_def = self.create_def(async_id,
|
||||||
|
DefPathData::ClosureExpr,
|
||||||
|
REGULAR_SPACE,
|
||||||
|
expr.span);
|
||||||
|
self.parent_def = Some(async_def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExprKind::Async(_, async_id, _) => {
|
||||||
|
let async_def = self.create_def(async_id,
|
||||||
|
DefPathData::ClosureExpr,
|
||||||
|
REGULAR_SPACE,
|
||||||
|
expr.span);
|
||||||
|
self.parent_def = Some(async_def);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
};
|
||||||
|
|
||||||
visit::walk_expr(self, expr);
|
visit::walk_expr(self, expr);
|
||||||
self.parent_def = parent_def;
|
self.parent_def = parent_def;
|
||||||
|
@ -245,6 +245,16 @@ pub enum LifetimeName {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LifetimeName {
|
impl LifetimeName {
|
||||||
|
pub fn is_elided(self) -> bool {
|
||||||
|
match self {
|
||||||
|
LifetimeName::Implicit
|
||||||
|
| LifetimeName::Underscore => true,
|
||||||
|
LifetimeName::Fresh(_)
|
||||||
|
| LifetimeName::Static
|
||||||
|
| LifetimeName::Name(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> Name {
|
pub fn name(&self) -> Name {
|
||||||
use self::LifetimeName::*;
|
use self::LifetimeName::*;
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -409,6 +409,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat {
|
|||||||
});
|
});
|
||||||
|
|
||||||
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
|
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
|
||||||
|
Async,
|
||||||
DotFill,
|
DotFill,
|
||||||
QuestionMark,
|
QuestionMark,
|
||||||
ExistentialReturnType,
|
ExistentialReturnType,
|
||||||
|
@ -1245,7 +1245,10 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
|||||||
(has_types || tcx.codegen_fn_attrs(def_id).requests_inline()) &&
|
(has_types || tcx.codegen_fn_attrs(def_id).requests_inline()) &&
|
||||||
!self.metadata_output_only();
|
!self.metadata_output_only();
|
||||||
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
|
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
|
||||||
if needs_inline || header.constness == hir::Constness::Const || always_encode_mir {
|
if needs_inline
|
||||||
|
|| header.constness == hir::Constness::Const
|
||||||
|
|| always_encode_mir
|
||||||
|
{
|
||||||
self.encode_optimized_mir(def_id)
|
self.encode_optimized_mir(def_id)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -55,7 +55,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
|
|||||||
|
|
||||||
use syntax::visit::{self, FnKind, Visitor};
|
use syntax::visit::{self, FnKind, Visitor};
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind};
|
use syntax::ast::{Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind, FnHeader};
|
||||||
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
|
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
|
||||||
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
|
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
|
||||||
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
|
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
|
||||||
@ -2054,13 +2054,54 @@ impl<'a> Resolver<'a> {
|
|||||||
self.check_proc_macro_attrs(&item.attrs);
|
self.check_proc_macro_attrs(&item.attrs);
|
||||||
|
|
||||||
match item.node {
|
match item.node {
|
||||||
|
ItemKind::Fn(ref declaration,
|
||||||
|
FnHeader { asyncness: IsAsync::Async(async_closure_id), .. },
|
||||||
|
ref generics,
|
||||||
|
ref body) => {
|
||||||
|
// Async functions are desugared from `async fn foo() { .. }`
|
||||||
|
// to `fn foo() { future_from_generator(move || ... ) }`,
|
||||||
|
// so we have to visit the body inside the closure scope
|
||||||
|
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
|
||||||
|
this.visit_vis(&item.vis);
|
||||||
|
this.visit_ident(item.ident);
|
||||||
|
this.visit_generics(generics);
|
||||||
|
let rib_kind = ItemRibKind;
|
||||||
|
this.ribs[ValueNS].push(Rib::new(rib_kind));
|
||||||
|
this.label_ribs.push(Rib::new(rib_kind));
|
||||||
|
let mut bindings_list = FxHashMap();
|
||||||
|
for argument in &declaration.inputs {
|
||||||
|
this.resolve_pattern(
|
||||||
|
&argument.pat, PatternSource::FnParam, &mut bindings_list);
|
||||||
|
this.visit_ty(&*argument.ty);
|
||||||
|
}
|
||||||
|
visit::walk_fn_ret_ty(this, &declaration.output);
|
||||||
|
|
||||||
|
// Now resolve the inner closure
|
||||||
|
{
|
||||||
|
let rib_kind = ClosureRibKind(async_closure_id);
|
||||||
|
this.ribs[ValueNS].push(Rib::new(rib_kind));
|
||||||
|
this.label_ribs.push(Rib::new(rib_kind));
|
||||||
|
// No need to resolve either arguments nor return type,
|
||||||
|
// as this closure has neither
|
||||||
|
|
||||||
|
// Resolve the body
|
||||||
|
this.visit_block(body);
|
||||||
|
this.label_ribs.pop();
|
||||||
|
this.ribs[ValueNS].pop();
|
||||||
|
}
|
||||||
|
this.label_ribs.pop();
|
||||||
|
this.ribs[ValueNS].pop();
|
||||||
|
|
||||||
|
walk_list!(this, visit_attribute, &item.attrs);
|
||||||
|
})
|
||||||
|
}
|
||||||
ItemKind::Enum(_, ref generics) |
|
ItemKind::Enum(_, ref generics) |
|
||||||
ItemKind::Ty(_, ref generics) |
|
ItemKind::Ty(_, ref generics) |
|
||||||
ItemKind::Struct(_, ref generics) |
|
ItemKind::Struct(_, ref generics) |
|
||||||
ItemKind::Union(_, ref generics) |
|
ItemKind::Union(_, ref generics) |
|
||||||
ItemKind::Fn(.., ref generics, _) => {
|
ItemKind::Fn(_, _, ref generics, _) => {
|
||||||
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind),
|
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind),
|
||||||
|this| visit::walk_item(this, item));
|
|this| visit::walk_item(this, item));
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
|
ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
|
||||||
@ -3888,6 +3929,49 @@ impl<'a> Resolver<'a> {
|
|||||||
visit::walk_expr(self, expr);
|
visit::walk_expr(self, expr);
|
||||||
self.current_type_ascription.pop();
|
self.current_type_ascription.pop();
|
||||||
}
|
}
|
||||||
|
// Resolve the body of async exprs inside the async closure to which they desugar
|
||||||
|
ExprKind::Async(_, async_closure_id, ref block) => {
|
||||||
|
let rib_kind = ClosureRibKind(async_closure_id);
|
||||||
|
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
||||||
|
self.label_ribs.push(Rib::new(rib_kind));
|
||||||
|
self.visit_block(&block);
|
||||||
|
self.label_ribs.pop();
|
||||||
|
self.ribs[ValueNS].pop();
|
||||||
|
}
|
||||||
|
// `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
|
||||||
|
// resolve the arguments within the proper scopes so that usages of them inside the
|
||||||
|
// closure are detected as upvars rather than normal closure arg usages.
|
||||||
|
ExprKind::Closure(
|
||||||
|
_, IsAsync::Async(inner_closure_id), _, ref fn_decl, ref body, _span) =>
|
||||||
|
{
|
||||||
|
let rib_kind = ClosureRibKind(expr.id);
|
||||||
|
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
||||||
|
self.label_ribs.push(Rib::new(rib_kind));
|
||||||
|
// Resolve arguments:
|
||||||
|
let mut bindings_list = FxHashMap();
|
||||||
|
for argument in &fn_decl.inputs {
|
||||||
|
self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
|
||||||
|
self.visit_ty(&argument.ty);
|
||||||
|
}
|
||||||
|
// No need to resolve return type-- the outer closure return type is
|
||||||
|
// FunctionRetTy::Default
|
||||||
|
|
||||||
|
// Now resolve the inner closure
|
||||||
|
{
|
||||||
|
let rib_kind = ClosureRibKind(inner_closure_id);
|
||||||
|
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
||||||
|
self.label_ribs.push(Rib::new(rib_kind));
|
||||||
|
// No need to resolve arguments: the inner closure has none.
|
||||||
|
// Resolve the return type:
|
||||||
|
visit::walk_fn_ret_ty(self, &fn_decl.output);
|
||||||
|
// Resolve the body
|
||||||
|
self.visit_expr(body);
|
||||||
|
self.label_ribs.pop();
|
||||||
|
self.ribs[ValueNS].pop();
|
||||||
|
}
|
||||||
|
self.label_ribs.pop();
|
||||||
|
self.ribs[ValueNS].pop();
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
visit::walk_expr(self, expr);
|
visit::walk_expr(self, expr);
|
||||||
}
|
}
|
||||||
|
@ -1555,7 +1555,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ExprKind::Closure(_, _, ref decl, ref body, _fn_decl_span) => {
|
ast::ExprKind::Closure(_, _, _, ref decl, ref body, _fn_decl_span) => {
|
||||||
let mut id = String::from("$");
|
let mut id = String::from("$");
|
||||||
id.push_str(&ex.id.to_string());
|
id.push_str(&ex.id.to_string());
|
||||||
|
|
||||||
|
@ -385,7 +385,7 @@ impl Sig for ast::Item {
|
|||||||
if header.constness.node == ast::Constness::Const {
|
if header.constness.node == ast::Constness::Const {
|
||||||
text.push_str("const ");
|
text.push_str("const ");
|
||||||
}
|
}
|
||||||
if header.asyncness == ast::IsAsync::Async {
|
if header.asyncness.is_async() {
|
||||||
text.push_str("async ");
|
text.push_str("async ");
|
||||||
}
|
}
|
||||||
if header.unsafety == ast::Unsafety::Unsafe {
|
if header.unsafety == ast::Unsafety::Unsafe {
|
||||||
@ -920,7 +920,7 @@ fn make_method_signature(
|
|||||||
if m.header.constness.node == ast::Constness::Const {
|
if m.header.constness.node == ast::Constness::Const {
|
||||||
text.push_str("const ");
|
text.push_str("const ");
|
||||||
}
|
}
|
||||||
if m.header.asyncness == ast::IsAsync::Async {
|
if m.header.asyncness.is_async() {
|
||||||
text.push_str("async ");
|
text.push_str("async ");
|
||||||
}
|
}
|
||||||
if m.header.unsafety == ast::Unsafety::Unsafe {
|
if m.header.unsafety == ast::Unsafety::Unsafe {
|
||||||
|
@ -1164,7 +1164,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) {
|
if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) {
|
||||||
if let Item_::ItemFn(_, _, _, _, ref generics, _) = item.node {
|
if let Item_::ItemFn(_, _, ref generics, _) = item.node {
|
||||||
if !generics.params.is_empty() {
|
if !generics.params.is_empty() {
|
||||||
fcx.tcx.sess.span_err(
|
fcx.tcx.sess.span_err(
|
||||||
span,
|
span,
|
||||||
|
@ -2585,7 +2585,8 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
|||||||
write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it)?)?;
|
write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it)?)?;
|
||||||
render_attributes(w, it)?;
|
render_attributes(w, it)?;
|
||||||
write!(w,
|
write!(w,
|
||||||
"{vis}{constness}{asyncness}{unsafety}{abi}fn {name}{generics}{decl}{where_clause}</pre>",
|
"{vis}{constness}{asyncness}{unsafety}{abi}fn \
|
||||||
|
{name}{generics}{decl}{where_clause}</pre>",
|
||||||
vis = VisSpace(&it.visibility),
|
vis = VisSpace(&it.visibility),
|
||||||
constness = ConstnessSpace(f.header.constness),
|
constness = ConstnessSpace(f.header.constness),
|
||||||
asyncness = AsyncSpace(f.header.asyncness),
|
asyncness = AsyncSpace(f.header.asyncness),
|
||||||
|
@ -263,6 +263,7 @@
|
|||||||
#![feature(fn_traits)]
|
#![feature(fn_traits)]
|
||||||
#![feature(fnbox)]
|
#![feature(fnbox)]
|
||||||
#![feature(futures_api)]
|
#![feature(futures_api)]
|
||||||
|
#![feature(generator_trait)]
|
||||||
#![feature(hashmap_internals)]
|
#![feature(hashmap_internals)]
|
||||||
#![feature(int_error_internals)]
|
#![feature(int_error_internals)]
|
||||||
#![feature(integer_atomics)]
|
#![feature(integer_atomics)]
|
||||||
@ -410,8 +411,6 @@ pub use core::ops;
|
|||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use core::ptr;
|
pub use core::ptr;
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use core::raw;
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub use core::result;
|
pub use core::result;
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use core::option;
|
pub use core::option;
|
||||||
@ -496,6 +495,7 @@ pub mod os;
|
|||||||
pub mod panic;
|
pub mod panic;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
|
pub mod raw;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
|
|
||||||
|
@ -213,6 +213,26 @@ macro_rules! eprintln {
|
|||||||
($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
|
($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[unstable(feature = "await_macro", issue = "50547")]
|
||||||
|
#[allow_internal_unstable]
|
||||||
|
macro_rules! await {
|
||||||
|
($e:expr) => { {
|
||||||
|
let mut pinned = $e;
|
||||||
|
let mut pinned = unsafe { ::core::mem::PinMut::new_unchecked(&mut pinned) };
|
||||||
|
loop {
|
||||||
|
match ::std::raw::with_get_cx(|cx|
|
||||||
|
::core::future::Future::poll(pinned.reborrow(), cx))
|
||||||
|
{
|
||||||
|
// FIXME(cramertj) prior to stabilizing await, we have to ensure that this
|
||||||
|
// can't be used to create a generator on stable via `|| await!()`.
|
||||||
|
::core::task::Poll::Pending => yield,
|
||||||
|
::core::task::Poll::Ready(x) => break x,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
||||||
/// A macro to select an event from a number of receivers.
|
/// A macro to select an event from a number of receivers.
|
||||||
///
|
///
|
||||||
/// This macro is used to wait for the first event to occur on a number of
|
/// This macro is used to wait for the first event to occur on a number of
|
||||||
|
110
src/libstd/raw.rs
Normal file
110
src/libstd/raw.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![allow(missing_docs)]
|
||||||
|
#![unstable(feature = "raw", issue = "27751")]
|
||||||
|
|
||||||
|
//! Contains struct definitions for the layout of compiler built-in types.
|
||||||
|
//!
|
||||||
|
//! They can be used as targets of transmutes in unsafe code for manipulating
|
||||||
|
//! the raw representations directly.
|
||||||
|
//!
|
||||||
|
//! Their definition should always match the ABI defined in `rustc::back::abi`.
|
||||||
|
|
||||||
|
use core::cell::Cell;
|
||||||
|
use core::future::Future;
|
||||||
|
use core::marker::Unpin;
|
||||||
|
use core::mem::PinMut;
|
||||||
|
use core::option::Option;
|
||||||
|
use core::ptr::NonNull;
|
||||||
|
use core::task::{self, Poll};
|
||||||
|
use core::ops::{Drop, Generator, GeneratorState};
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
pub use core::raw::*;
|
||||||
|
|
||||||
|
/// Wrap a future in a generator.
|
||||||
|
///
|
||||||
|
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
|
||||||
|
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
|
||||||
|
#[unstable(feature = "gen_future", issue = "50547")]
|
||||||
|
pub fn future_from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
|
||||||
|
GenFuture(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A wrapper around generators used to implement `Future` for `async`/`await` code.
|
||||||
|
#[unstable(feature = "gen_future", issue = "50547")]
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
|
struct GenFuture<T: Generator<Yield = ()>>(T);
|
||||||
|
|
||||||
|
// We rely on the fact that async/await futures are immovable in order to create
|
||||||
|
// self-referential borrows in the underlying generator.
|
||||||
|
impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}
|
||||||
|
|
||||||
|
#[unstable(feature = "gen_future", issue = "50547")]
|
||||||
|
impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
|
||||||
|
type Output = T::Return;
|
||||||
|
fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
|
||||||
|
with_set_cx(cx, || match unsafe { PinMut::get_mut(self).0.resume() } {
|
||||||
|
GeneratorState::Yielded(()) => Poll::Pending,
|
||||||
|
GeneratorState::Complete(x) => Poll::Ready(x),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
static TLS_CX: Cell<Option<NonNull<task::Context<'static>>>> = Cell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SetOnDrop(Option<NonNull<task::Context<'static>>>);
|
||||||
|
|
||||||
|
impl Drop for SetOnDrop {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
TLS_CX.with(|tls_cx| {
|
||||||
|
tls_cx.set(self.0.take());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "gen_future", issue = "50547")]
|
||||||
|
pub fn with_set_cx<F, R>(cx: &mut task::Context, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce() -> R
|
||||||
|
{
|
||||||
|
let old_cx = TLS_CX.with(|tls_cx| {
|
||||||
|
let old_cx = tls_cx.get();
|
||||||
|
tls_cx.set(NonNull::new(
|
||||||
|
cx as *mut task::Context as *mut () as *mut task::Context<'static>));
|
||||||
|
old_cx
|
||||||
|
});
|
||||||
|
let _reset_cx = SetOnDrop(old_cx);
|
||||||
|
let res = f();
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "gen_future", issue = "50547")]
|
||||||
|
pub fn with_get_cx<F, R>(f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut task::Context) -> R
|
||||||
|
{
|
||||||
|
let cx_ptr = TLS_CX.with(|tls_cx| {
|
||||||
|
let cx_ptr = tls_cx.get();
|
||||||
|
// Clear the entry so that nested `with_get_cx` calls
|
||||||
|
// will fail or set their own value.
|
||||||
|
tls_cx.set(None);
|
||||||
|
cx_ptr
|
||||||
|
});
|
||||||
|
let _reset_cx = SetOnDrop(cx_ptr);
|
||||||
|
|
||||||
|
let mut cx_ptr = cx_ptr.expect(
|
||||||
|
"TLS task::Context not set. This is a rustc bug. \
|
||||||
|
Please file an issue on https://github.com/rust-lang/rust.");
|
||||||
|
unsafe { f(cx_ptr.as_mut()) }
|
||||||
|
}
|
@ -987,6 +987,7 @@ impl Expr {
|
|||||||
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
||||||
ExprKind::Block(..) => ExprPrecedence::Block,
|
ExprKind::Block(..) => ExprPrecedence::Block,
|
||||||
ExprKind::Catch(..) => ExprPrecedence::Catch,
|
ExprKind::Catch(..) => ExprPrecedence::Catch,
|
||||||
|
ExprKind::Async(..) => ExprPrecedence::Async,
|
||||||
ExprKind::Assign(..) => ExprPrecedence::Assign,
|
ExprKind::Assign(..) => ExprPrecedence::Assign,
|
||||||
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
|
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
|
||||||
ExprKind::Field(..) => ExprPrecedence::Field,
|
ExprKind::Field(..) => ExprPrecedence::Field,
|
||||||
@ -1094,9 +1095,18 @@ pub enum ExprKind {
|
|||||||
/// A closure (for example, `move |a, b, c| a + b + c`)
|
/// A closure (for example, `move |a, b, c| a + b + c`)
|
||||||
///
|
///
|
||||||
/// The final span is the span of the argument block `|...|`
|
/// The final span is the span of the argument block `|...|`
|
||||||
Closure(CaptureBy, Movability, P<FnDecl>, P<Expr>, Span),
|
Closure(CaptureBy, IsAsync, Movability, P<FnDecl>, P<Expr>, Span),
|
||||||
/// A block (`'label: { ... }`)
|
/// A block (`'label: { ... }`)
|
||||||
Block(P<Block>, Option<Label>),
|
Block(P<Block>, Option<Label>),
|
||||||
|
/// An async block (`async move { ... }`)
|
||||||
|
///
|
||||||
|
/// The `NodeId` is the `NodeId` for the closure that results from
|
||||||
|
/// desugaring an async block, just like the NodeId field in the
|
||||||
|
/// `IsAsync` enum. This is necessary in order to create a def for the
|
||||||
|
/// closure which can be used as a parent of any child defs. Defs
|
||||||
|
/// created during lowering cannot be made the parent of any other
|
||||||
|
/// preexisting defs.
|
||||||
|
Async(CaptureBy, NodeId, P<Block>),
|
||||||
/// A catch block (`catch { ... }`)
|
/// A catch block (`catch { ... }`)
|
||||||
Catch(P<Block>),
|
Catch(P<Block>),
|
||||||
|
|
||||||
@ -1708,10 +1718,20 @@ pub enum Unsafety {
|
|||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||||
pub enum IsAsync {
|
pub enum IsAsync {
|
||||||
Async,
|
Async(NodeId),
|
||||||
NotAsync,
|
NotAsync,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IsAsync {
|
||||||
|
pub fn is_async(self) -> bool {
|
||||||
|
if let IsAsync::Async(_) = self {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||||
pub enum Constness {
|
pub enum Constness {
|
||||||
Const,
|
Const,
|
||||||
|
@ -915,6 +915,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||||||
fn_decl_span: Span) // span of the `|...|` part
|
fn_decl_span: Span) // span of the `|...|` part
|
||||||
-> P<ast::Expr> {
|
-> P<ast::Expr> {
|
||||||
self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref,
|
self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref,
|
||||||
|
ast::IsAsync::NotAsync,
|
||||||
ast::Movability::Movable,
|
ast::Movability::Movable,
|
||||||
fn_decl,
|
fn_decl,
|
||||||
body,
|
body,
|
||||||
@ -935,6 +936,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||||||
// the entire lambda body. Probably we should extend the API
|
// the entire lambda body. Probably we should extend the API
|
||||||
// here, but that's not entirely clear.
|
// here, but that's not entirely clear.
|
||||||
self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref,
|
self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref,
|
||||||
|
ast::IsAsync::NotAsync,
|
||||||
ast::Movability::Movable,
|
ast::Movability::Movable,
|
||||||
fn_decl,
|
fn_decl,
|
||||||
body,
|
body,
|
||||||
|
@ -308,7 +308,7 @@ declare_features! (
|
|||||||
// Declarative macros 2.0 (`macro`).
|
// Declarative macros 2.0 (`macro`).
|
||||||
(active, decl_macro, "1.17.0", Some(39412), None),
|
(active, decl_macro, "1.17.0", Some(39412), None),
|
||||||
|
|
||||||
// Allows #[link(kind="static-nobundle"...]
|
// Allows #[link(kind="static-nobundle"...)]
|
||||||
(active, static_nobundle, "1.16.0", Some(37403), None),
|
(active, static_nobundle, "1.16.0", Some(37403), None),
|
||||||
|
|
||||||
// `extern "msp430-interrupt" fn()`
|
// `extern "msp430-interrupt" fn()`
|
||||||
@ -474,7 +474,7 @@ declare_features! (
|
|||||||
(active, doc_keyword, "1.28.0", Some(51315), None),
|
(active, doc_keyword, "1.28.0", Some(51315), None),
|
||||||
|
|
||||||
// Allows async and await syntax
|
// Allows async and await syntax
|
||||||
(active, async_await, "1.28.0", Some(0), Some(Edition::Edition2018)),
|
(active, async_await, "1.28.0", Some(50547), None),
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_features! (
|
declare_features! (
|
||||||
@ -1722,6 +1722,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||||||
"labels on blocks are unstable");
|
"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");
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
visit::walk_expr(self, e);
|
visit::walk_expr(self, e);
|
||||||
@ -1764,7 +1770,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||||||
match fn_kind {
|
match fn_kind {
|
||||||
FnKind::ItemFn(_, header, _, _) => {
|
FnKind::ItemFn(_, header, _, _) => {
|
||||||
// check for const fn and async fn declarations
|
// check for const fn and async fn declarations
|
||||||
if header.asyncness == ast::IsAsync::Async {
|
if header.asyncness.is_async() {
|
||||||
gate_feature_post!(&self, async_await, span, "async fn is unstable");
|
gate_feature_post!(&self, async_await, span, "async fn is unstable");
|
||||||
}
|
}
|
||||||
if header.constness.node == ast::Constness::Const {
|
if header.constness.node == ast::Constness::Const {
|
||||||
|
@ -76,6 +76,10 @@ pub trait Folder : Sized {
|
|||||||
noop_fold_item_simple(i, self)
|
noop_fold_item_simple(i, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold_fn_header(&mut self, header: FnHeader) -> FnHeader {
|
||||||
|
noop_fold_fn_header(header, self)
|
||||||
|
}
|
||||||
|
|
||||||
fn fold_struct_field(&mut self, sf: StructField) -> StructField {
|
fn fold_struct_field(&mut self, sf: StructField) -> StructField {
|
||||||
noop_fold_struct_field(sf, self)
|
noop_fold_struct_field(sf, self)
|
||||||
}
|
}
|
||||||
@ -883,6 +887,7 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
|
|||||||
}
|
}
|
||||||
ItemKind::Fn(decl, header, generics, body) => {
|
ItemKind::Fn(decl, header, generics, body) => {
|
||||||
let generics = folder.fold_generics(generics);
|
let generics = folder.fold_generics(generics);
|
||||||
|
let header = folder.fold_fn_header(header);
|
||||||
let decl = folder.fold_fn_decl(decl);
|
let decl = folder.fold_fn_decl(decl);
|
||||||
let body = folder.fold_block(body);
|
let body = folder.fold_block(body);
|
||||||
ItemKind::Fn(decl, header, generics, body)
|
ItemKind::Fn(decl, header, generics, body)
|
||||||
@ -990,6 +995,14 @@ pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T)
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn noop_fold_fn_header<T: Folder>(mut header: FnHeader, folder: &mut T) -> FnHeader {
|
||||||
|
header.asyncness = match header.asyncness {
|
||||||
|
IsAsync::Async(node_id) => IsAsync::Async(folder.new_id(node_id)),
|
||||||
|
IsAsync::NotAsync => IsAsync::NotAsync,
|
||||||
|
};
|
||||||
|
header
|
||||||
|
}
|
||||||
|
|
||||||
pub fn noop_fold_mod<T: Folder>(Mod {inner, items}: Mod, folder: &mut T) -> Mod {
|
pub fn noop_fold_mod<T: Folder>(Mod {inner, items}: Mod, folder: &mut T) -> Mod {
|
||||||
Mod {
|
Mod {
|
||||||
inner: folder.new_span(inner),
|
inner: folder.new_span(inner),
|
||||||
@ -1082,7 +1095,7 @@ pub fn noop_fold_foreign_item_simple<T: Folder>(ni: ForeignItem, folder: &mut T)
|
|||||||
|
|
||||||
pub fn noop_fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> MethodSig {
|
pub fn noop_fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> MethodSig {
|
||||||
MethodSig {
|
MethodSig {
|
||||||
header: sig.header,
|
header: folder.fold_fn_header(sig.header),
|
||||||
decl: folder.fold_fn_decl(sig.decl)
|
decl: folder.fold_fn_decl(sig.decl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1235,8 +1248,13 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
|
|||||||
ExprKind::Match(folder.fold_expr(expr),
|
ExprKind::Match(folder.fold_expr(expr),
|
||||||
arms.move_map(|x| folder.fold_arm(x)))
|
arms.move_map(|x| folder.fold_arm(x)))
|
||||||
}
|
}
|
||||||
ExprKind::Closure(capture_clause, movability, decl, body, span) => {
|
ExprKind::Closure(capture_clause, asyncness, movability, decl, body, span) => {
|
||||||
|
let asyncness = match asyncness {
|
||||||
|
IsAsync::Async(node_id) => IsAsync::Async(folder.new_id(node_id)),
|
||||||
|
IsAsync::NotAsync => IsAsync::NotAsync,
|
||||||
|
};
|
||||||
ExprKind::Closure(capture_clause,
|
ExprKind::Closure(capture_clause,
|
||||||
|
asyncness,
|
||||||
movability,
|
movability,
|
||||||
folder.fold_fn_decl(decl),
|
folder.fold_fn_decl(decl),
|
||||||
folder.fold_expr(body),
|
folder.fold_expr(body),
|
||||||
@ -1246,6 +1264,9 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
|
|||||||
ExprKind::Block(folder.fold_block(blk),
|
ExprKind::Block(folder.fold_block(blk),
|
||||||
opt_label.map(|label| folder.fold_label(label)))
|
opt_label.map(|label| folder.fold_label(label)))
|
||||||
}
|
}
|
||||||
|
ExprKind::Async(capture_clause, node_id, body) => {
|
||||||
|
ExprKind::Async(capture_clause, folder.new_id(node_id), folder.fold_block(body))
|
||||||
|
}
|
||||||
ExprKind::Assign(el, er) => {
|
ExprKind::Assign(el, er) => {
|
||||||
ExprKind::Assign(folder.fold_expr(el), folder.fold_expr(er))
|
ExprKind::Assign(folder.fold_expr(el), folder.fold_expr(er))
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ use ast::{BinOpKind, UnOp};
|
|||||||
use ast::{RangeEnd, RangeSyntax};
|
use ast::{RangeEnd, RangeSyntax};
|
||||||
use {ast, attr};
|
use {ast, attr};
|
||||||
use codemap::{self, CodeMap, Spanned, respan};
|
use codemap::{self, CodeMap, Spanned, respan};
|
||||||
use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, DUMMY_SP};
|
use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, DUMMY_SP, edition::Edition};
|
||||||
use errors::{self, Applicability, DiagnosticBuilder};
|
use errors::{self, Applicability, DiagnosticBuilder};
|
||||||
use parse::{self, SeqSep, classify, token};
|
use parse::{self, SeqSep, classify, token};
|
||||||
use parse::lexer::TokenAndSpan;
|
use parse::lexer::TokenAndSpan;
|
||||||
@ -2258,6 +2258,15 @@ impl<'a> Parser<'a> {
|
|||||||
hi = path.span;
|
hi = path.span;
|
||||||
return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs));
|
return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs));
|
||||||
}
|
}
|
||||||
|
if syntax_pos::hygiene::default_edition() >= Edition::Edition2018 &&
|
||||||
|
self.check_keyword(keywords::Async)
|
||||||
|
{
|
||||||
|
if self.is_async_block() { // check for `async {` and `async move {`
|
||||||
|
return self.parse_async_block(attrs);
|
||||||
|
} else {
|
||||||
|
return self.parse_lambda_expr(attrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
if self.check_keyword(keywords::Move) || self.check_keyword(keywords::Static) {
|
if self.check_keyword(keywords::Move) || self.check_keyword(keywords::Static) {
|
||||||
return self.parse_lambda_expr(attrs);
|
return self.parse_lambda_expr(attrs);
|
||||||
}
|
}
|
||||||
@ -3252,6 +3261,13 @@ impl<'a> Parser<'a> {
|
|||||||
} else {
|
} else {
|
||||||
Movability::Movable
|
Movability::Movable
|
||||||
};
|
};
|
||||||
|
let asyncness = if syntax_pos::hygiene::default_edition() >= Edition::Edition2018
|
||||||
|
&& self.eat_keyword(keywords::Async)
|
||||||
|
{
|
||||||
|
IsAsync::Async(ast::DUMMY_NODE_ID)
|
||||||
|
} else {
|
||||||
|
IsAsync::NotAsync
|
||||||
|
};
|
||||||
let capture_clause = if self.eat_keyword(keywords::Move) {
|
let capture_clause = if self.eat_keyword(keywords::Move) {
|
||||||
CaptureBy::Value
|
CaptureBy::Value
|
||||||
} else {
|
} else {
|
||||||
@ -3274,7 +3290,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
Ok(self.mk_expr(
|
Ok(self.mk_expr(
|
||||||
lo.to(body.span),
|
lo.to(body.span),
|
||||||
ExprKind::Closure(capture_clause, movability, decl, body, lo.to(decl_hi)),
|
ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)),
|
||||||
attrs))
|
attrs))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3352,6 +3368,24 @@ impl<'a> Parser<'a> {
|
|||||||
Ok(self.mk_expr(span, ExprKind::Loop(body, opt_label), attrs))
|
Ok(self.mk_expr(span, ExprKind::Loop(body, opt_label), attrs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse an `async move {...}` expression
|
||||||
|
pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>)
|
||||||
|
-> PResult<'a, P<Expr>>
|
||||||
|
{
|
||||||
|
let span_lo = self.span;
|
||||||
|
self.expect_keyword(keywords::Async)?;
|
||||||
|
let capture_clause = if self.eat_keyword(keywords::Move) {
|
||||||
|
CaptureBy::Value
|
||||||
|
} else {
|
||||||
|
CaptureBy::Ref
|
||||||
|
};
|
||||||
|
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
|
||||||
|
attrs.extend(iattrs);
|
||||||
|
Ok(self.mk_expr(
|
||||||
|
span_lo.to(body.span),
|
||||||
|
ExprKind::Async(capture_clause, ast::DUMMY_NODE_ID, body), attrs))
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a `do catch {...}` expression (`do catch` token already eaten)
|
/// Parse a `do catch {...}` expression (`do catch` token already eaten)
|
||||||
fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
|
fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
|
||||||
-> PResult<'a, P<Expr>>
|
-> PResult<'a, P<Expr>>
|
||||||
@ -4286,6 +4320,18 @@ impl<'a> Parser<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_async_block(&mut self) -> bool {
|
||||||
|
self.token.is_keyword(keywords::Async) &&
|
||||||
|
(
|
||||||
|
( // `async move {`
|
||||||
|
self.look_ahead(1, |t| t.is_keyword(keywords::Move)) &&
|
||||||
|
self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))
|
||||||
|
) || ( // `async {`
|
||||||
|
self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn is_catch_expr(&mut self) -> bool {
|
fn is_catch_expr(&mut self) -> bool {
|
||||||
self.token.is_keyword(keywords::Do) &&
|
self.token.is_keyword(keywords::Do) &&
|
||||||
self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) &&
|
self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) &&
|
||||||
@ -6698,14 +6744,18 @@ impl<'a> Parser<'a> {
|
|||||||
maybe_append(attrs, extra_attrs));
|
maybe_append(attrs, extra_attrs));
|
||||||
return Ok(Some(item));
|
return Ok(Some(item));
|
||||||
}
|
}
|
||||||
if self.eat_keyword(keywords::Async) {
|
if self.check_keyword(keywords::Async) &&
|
||||||
|
(self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) ||
|
||||||
|
self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)))
|
||||||
|
{
|
||||||
// ASYNC FUNCTION ITEM
|
// ASYNC FUNCTION ITEM
|
||||||
|
self.expect_keyword(keywords::Async)?;
|
||||||
let unsafety = self.parse_unsafety();
|
let unsafety = self.parse_unsafety();
|
||||||
self.expect_keyword(keywords::Fn)?;
|
self.expect_keyword(keywords::Fn)?;
|
||||||
let fn_span = self.prev_span;
|
let fn_span = self.prev_span;
|
||||||
let (ident, item_, extra_attrs) =
|
let (ident, item_, extra_attrs) =
|
||||||
self.parse_item_fn(unsafety,
|
self.parse_item_fn(unsafety,
|
||||||
IsAsync::Async,
|
IsAsync::Async(ast::DUMMY_NODE_ID),
|
||||||
respan(fn_span, Constness::NotConst),
|
respan(fn_span, Constness::NotConst),
|
||||||
Abi::Rust)?;
|
Abi::Rust)?;
|
||||||
let prev_span = self.prev_span;
|
let prev_span = self.prev_span;
|
||||||
|
@ -2171,8 +2171,10 @@ impl<'a> State<'a> {
|
|||||||
}
|
}
|
||||||
self.bclose_(expr.span, INDENT_UNIT)?;
|
self.bclose_(expr.span, INDENT_UNIT)?;
|
||||||
}
|
}
|
||||||
ast::ExprKind::Closure(capture_clause, movability, ref decl, ref body, _) => {
|
ast::ExprKind::Closure(
|
||||||
|
capture_clause, asyncness, movability, ref decl, ref body, _) => {
|
||||||
self.print_movability(movability)?;
|
self.print_movability(movability)?;
|
||||||
|
self.print_asyncness(asyncness)?;
|
||||||
self.print_capture_clause(capture_clause)?;
|
self.print_capture_clause(capture_clause)?;
|
||||||
|
|
||||||
self.print_fn_block_args(decl)?;
|
self.print_fn_block_args(decl)?;
|
||||||
@ -2196,6 +2198,12 @@ impl<'a> State<'a> {
|
|||||||
self.ibox(0)?;
|
self.ibox(0)?;
|
||||||
self.print_block_with_attrs(blk, attrs)?;
|
self.print_block_with_attrs(blk, attrs)?;
|
||||||
}
|
}
|
||||||
|
ast::ExprKind::Async(capture_clause, _, ref blk) => {
|
||||||
|
self.word_nbsp("async")?;
|
||||||
|
self.print_capture_clause(capture_clause)?;
|
||||||
|
self.s.space()?;
|
||||||
|
self.print_block_with_attrs(blk, attrs)?;
|
||||||
|
}
|
||||||
ast::ExprKind::Assign(ref lhs, ref rhs) => {
|
ast::ExprKind::Assign(ref lhs, ref rhs) => {
|
||||||
let prec = AssocOp::Assign.precedence() as i8;
|
let prec = AssocOp::Assign.precedence() as i8;
|
||||||
self.print_expr_maybe_paren(lhs, prec + 1)?;
|
self.print_expr_maybe_paren(lhs, prec + 1)?;
|
||||||
@ -2792,6 +2800,14 @@ impl<'a> State<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn print_asyncness(&mut self, asyncness: ast::IsAsync)
|
||||||
|
-> io::Result<()> {
|
||||||
|
if asyncness.is_async() {
|
||||||
|
self.word_nbsp("async")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy)
|
pub fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy)
|
||||||
-> io::Result<()> {
|
-> io::Result<()> {
|
||||||
match capture_clause {
|
match capture_clause {
|
||||||
@ -3122,11 +3138,7 @@ impl<'a> State<'a> {
|
|||||||
ast::Constness::Const => self.word_nbsp("const")?
|
ast::Constness::Const => self.word_nbsp("const")?
|
||||||
}
|
}
|
||||||
|
|
||||||
match header.asyncness {
|
self.print_asyncness(header.asyncness)?;
|
||||||
ast::IsAsync::NotAsync => {}
|
|
||||||
ast::IsAsync::Async => self.word_nbsp("async")?
|
|
||||||
}
|
|
||||||
|
|
||||||
self.print_unsafety(header.unsafety)?;
|
self.print_unsafety(header.unsafety)?;
|
||||||
|
|
||||||
if header.abi != Abi::Rust {
|
if header.abi != Abi::Rust {
|
||||||
|
@ -95,6 +95,16 @@ impl<T: 'static> P<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> P<[T]> {
|
||||||
|
pub fn map_slice<F>(self, f: F) -> P<[T]> where
|
||||||
|
F: FnOnce(Vec<T>) -> Vec<T>
|
||||||
|
{
|
||||||
|
P {
|
||||||
|
ptr: f(self.ptr.into()).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: ?Sized> Deref for P<T> {
|
impl<T: ?Sized> Deref for P<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
|
@ -127,11 +127,17 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
|
|||||||
ast::ItemKind::Fn(_, header, _, _) => {
|
ast::ItemKind::Fn(_, header, _, _) => {
|
||||||
if header.unsafety == ast::Unsafety::Unsafe {
|
if header.unsafety == ast::Unsafety::Unsafe {
|
||||||
let diag = self.cx.span_diagnostic;
|
let diag = self.cx.span_diagnostic;
|
||||||
diag.span_fatal(i.span, "unsafe functions cannot be used for tests").raise();
|
diag.span_fatal(
|
||||||
|
i.span,
|
||||||
|
"unsafe functions cannot be used for tests"
|
||||||
|
).raise();
|
||||||
}
|
}
|
||||||
if header.asyncness == ast::IsAsync::Async {
|
if header.asyncness.is_async() {
|
||||||
let diag = self.cx.span_diagnostic;
|
let diag = self.cx.span_diagnostic;
|
||||||
diag.span_fatal(i.span, "async functions cannot be used for tests").raise();
|
diag.span_fatal(
|
||||||
|
i.span,
|
||||||
|
"async functions cannot be used for tests"
|
||||||
|
).raise();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {},
|
||||||
|
@ -277,6 +277,7 @@ pub enum ExprPrecedence {
|
|||||||
Block,
|
Block,
|
||||||
Catch,
|
Catch,
|
||||||
Struct,
|
Struct,
|
||||||
|
Async,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for ExprPrecedence {
|
impl PartialOrd for ExprPrecedence {
|
||||||
@ -346,6 +347,7 @@ impl ExprPrecedence {
|
|||||||
ExprPrecedence::Match |
|
ExprPrecedence::Match |
|
||||||
ExprPrecedence::Block |
|
ExprPrecedence::Block |
|
||||||
ExprPrecedence::Catch |
|
ExprPrecedence::Catch |
|
||||||
|
ExprPrecedence::Async |
|
||||||
ExprPrecedence::Struct => PREC_PAREN,
|
ExprPrecedence::Struct => PREC_PAREN,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
|||||||
}
|
}
|
||||||
ItemKind::Fn(ref declaration, header, ref generics, ref body) => {
|
ItemKind::Fn(ref declaration, header, ref generics, ref body) => {
|
||||||
visitor.visit_generics(generics);
|
visitor.visit_generics(generics);
|
||||||
visitor.visit_fn(FnKind::ItemFn(item.ident, header,
|
visitor.visit_fn(FnKind::ItemFn(item.ident, header,
|
||||||
&item.vis, body),
|
&item.vis, body),
|
||||||
declaration,
|
declaration,
|
||||||
item.span,
|
item.span,
|
||||||
@ -735,7 +735,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||||||
visitor.visit_expr(subexpression);
|
visitor.visit_expr(subexpression);
|
||||||
walk_list!(visitor, visit_arm, arms);
|
walk_list!(visitor, visit_arm, arms);
|
||||||
}
|
}
|
||||||
ExprKind::Closure(_, _, ref function_declaration, ref body, _decl_span) => {
|
ExprKind::Closure(_, _, _, ref function_declaration, ref body, _decl_span) => {
|
||||||
visitor.visit_fn(FnKind::Closure(body),
|
visitor.visit_fn(FnKind::Closure(body),
|
||||||
function_declaration,
|
function_declaration,
|
||||||
expression.span,
|
expression.span,
|
||||||
@ -745,6 +745,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||||||
walk_list!(visitor, visit_label, opt_label);
|
walk_list!(visitor, visit_label, opt_label);
|
||||||
visitor.visit_block(block);
|
visitor.visit_block(block);
|
||||||
}
|
}
|
||||||
|
ExprKind::Async(_, _, ref body) => {
|
||||||
|
visitor.visit_block(body);
|
||||||
|
}
|
||||||
ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
|
ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
|
||||||
visitor.visit_expr(left_hand_expression);
|
visitor.visit_expr(left_hand_expression);
|
||||||
visitor.visit_expr(right_hand_expression);
|
visitor.visit_expr(right_hand_expression);
|
||||||
|
@ -493,12 +493,14 @@ pub enum CompilerDesugaringKind {
|
|||||||
/// to an `existential type Foo: Trait;` + replacing the
|
/// to an `existential type Foo: Trait;` + replacing the
|
||||||
/// `impl Trait` with `Foo`.
|
/// `impl Trait` with `Foo`.
|
||||||
ExistentialReturnType,
|
ExistentialReturnType,
|
||||||
|
Async,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompilerDesugaringKind {
|
impl CompilerDesugaringKind {
|
||||||
pub fn as_symbol(&self) -> Symbol {
|
pub fn as_symbol(&self) -> Symbol {
|
||||||
use CompilerDesugaringKind::*;
|
use CompilerDesugaringKind::*;
|
||||||
let s = match *self {
|
let s = match *self {
|
||||||
|
Async => "async",
|
||||||
DotFill => "...",
|
DotFill => "...",
|
||||||
QuestionMark => "?",
|
QuestionMark => "?",
|
||||||
Catch => "do catch",
|
Catch => "do catch",
|
||||||
|
133
src/test/run-pass/async-await.rs
Normal file
133
src/test/run-pass/async-await.rs
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: --edition=2018
|
||||||
|
|
||||||
|
#![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)]
|
||||||
|
|
||||||
|
use std::boxed::PinBox;
|
||||||
|
use std::mem::PinMut;
|
||||||
|
use std::future::Future;
|
||||||
|
use std::sync::{
|
||||||
|
Arc,
|
||||||
|
atomic::{self, AtomicUsize},
|
||||||
|
};
|
||||||
|
use std::task::{
|
||||||
|
Context, Poll, Wake,
|
||||||
|
Executor, TaskObj, SpawnObjError,
|
||||||
|
local_waker_from_nonlocal,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Counter {
|
||||||
|
wakes: AtomicUsize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Wake for Counter {
|
||||||
|
fn wake(this: &Arc<Self>) {
|
||||||
|
this.wakes.fetch_add(1, atomic::Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NoopExecutor;
|
||||||
|
impl Executor for NoopExecutor {
|
||||||
|
fn spawn_obj(&mut self, _: TaskObj) -> Result<(), SpawnObjError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WakeOnceThenComplete(bool);
|
||||||
|
|
||||||
|
fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }
|
||||||
|
|
||||||
|
impl Future for WakeOnceThenComplete {
|
||||||
|
type Output = ();
|
||||||
|
fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<()> {
|
||||||
|
if self.0 {
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
cx.waker().wake();
|
||||||
|
self.0 = true;
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn async_block(x: u8) -> impl Future<Output = u8> {
|
||||||
|
async move {
|
||||||
|
await!(wake_and_yield_once());
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
|
||||||
|
async move {
|
||||||
|
let future = async {
|
||||||
|
await!(wake_and_yield_once());
|
||||||
|
x
|
||||||
|
};
|
||||||
|
await!(future)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn async_closure(x: u8) -> impl Future<Output = u8> {
|
||||||
|
(async move |x: u8| -> u8 {
|
||||||
|
await!(wake_and_yield_once());
|
||||||
|
x
|
||||||
|
})(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn async_fn(x: u8) -> u8 {
|
||||||
|
await!(wake_and_yield_once());
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn async_fn_with_borrow(x: &u8) -> u8 {
|
||||||
|
await!(wake_and_yield_once());
|
||||||
|
*x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
|
||||||
|
async move {
|
||||||
|
await!(async_fn_with_borrow(&y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_future_yields_once_then_returns<F, Fut>(f: F)
|
||||||
|
where
|
||||||
|
F: FnOnce(u8) -> Fut,
|
||||||
|
Fut: Future<Output = u8>,
|
||||||
|
{
|
||||||
|
let mut fut = PinBox::new(f(9));
|
||||||
|
let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
|
||||||
|
let waker = local_waker_from_nonlocal(counter.clone());
|
||||||
|
let executor = &mut NoopExecutor;
|
||||||
|
let cx = &mut Context::new(&waker, executor);
|
||||||
|
|
||||||
|
assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
|
||||||
|
assert_eq!(Poll::Pending, fut.as_pin_mut().poll(cx));
|
||||||
|
assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
|
||||||
|
assert_eq!(Poll::Ready(9), fut.as_pin_mut().poll(cx));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
macro_rules! test {
|
||||||
|
($($fn_name:ident,)*) => { $(
|
||||||
|
test_future_yields_once_then_returns($fn_name);
|
||||||
|
)* }
|
||||||
|
}
|
||||||
|
|
||||||
|
test! {
|
||||||
|
async_block,
|
||||||
|
async_nonmove_block,
|
||||||
|
async_closure,
|
||||||
|
async_fn,
|
||||||
|
async_fn_with_internal_borrow,
|
||||||
|
}
|
||||||
|
}
|
30
src/test/ui/async-fn-multiple-lifetimes.rs
Normal file
30
src/test/ui/async-fn-multiple-lifetimes.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: --edition=2018
|
||||||
|
|
||||||
|
#![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)]
|
||||||
|
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
|
async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
|
||||||
|
//~^ ERROR multiple different lifetimes used in arguments of `async fn`
|
||||||
|
|
||||||
|
async fn multiple_hrtb_and_single_named_lifetime_ok<'c>(
|
||||||
|
_: impl for<'a> Add<&'a u8>,
|
||||||
|
_: impl for<'b> Add<&'b u8>,
|
||||||
|
_: &'c u8,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
|
||||||
|
//~^ ERROR multiple elided lifetimes used
|
||||||
|
//~^^ ERROR missing lifetime specifier
|
||||||
|
|
||||||
|
fn main() {}
|
32
src/test/ui/async-fn-multiple-lifetimes.stderr
Normal file
32
src/test/ui/async-fn-multiple-lifetimes.stderr
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
error[E0703]: multiple different lifetimes used in arguments of `async fn`
|
||||||
|
--> $DIR/async-fn-multiple-lifetimes.rs:17:49
|
||||||
|
|
|
||||||
|
LL | async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
|
||||||
|
| --^^^^^^^^^-- different lifetime here
|
||||||
|
| |
|
||||||
|
| first lifetime here
|
||||||
|
|
|
||||||
|
= help: `async fn` can only accept borrowed values identical lifetimes
|
||||||
|
|
||||||
|
error[E0704]: multiple elided lifetimes used in arguments of `async fn`
|
||||||
|
--> $DIR/async-fn-multiple-lifetimes.rs:26:39
|
||||||
|
|
|
||||||
|
LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
|
||||||
|
| -^^^^^^^- different lifetime here
|
||||||
|
| |
|
||||||
|
| first lifetime here
|
||||||
|
|
|
||||||
|
= help: consider giving these arguments named lifetimes
|
||||||
|
|
||||||
|
error[E0106]: missing lifetime specifier
|
||||||
|
--> $DIR/async-fn-multiple-lifetimes.rs:26:39
|
||||||
|
|
|
||||||
|
LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
|
||||||
|
| ^ expected lifetime parameter
|
||||||
|
|
|
||||||
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_` or `_`
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors occurred: E0106, E0703, E0704.
|
||||||
|
For more information about an error, try `rustc --explain E0106`.
|
@ -25,7 +25,7 @@ pub fn check_async() {
|
|||||||
r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
|
r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
|
||||||
r#async = consumes_async_raw!(r#async); // OK
|
r#async = consumes_async_raw!(r#async); // OK
|
||||||
|
|
||||||
if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
|
if passes_ident!(async) == 1 {}
|
||||||
if passes_ident!(r#async) == 1 {} // OK
|
if passes_ident!(r#async) == 1 {} // OK
|
||||||
module::async(); //~ ERROR expected identifier, found reserved keyword `async`
|
module::async(); //~ ERROR expected identifier, found reserved keyword `async`
|
||||||
module::r#async(); // OK
|
module::r#async(); // OK
|
||||||
|
@ -22,11 +22,11 @@ error: no rules expected the token `async`
|
|||||||
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: expected expression, found reserved keyword `async`
|
error: expected one of `move`, `|`, or `||`, found `<eof>`
|
||||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:28:22
|
--> <passes_ident macros>:1:22
|
||||||
|
|
|
|
||||||
LL | if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
|
LL | ( $ i : ident ) => ( $ i )
|
||||||
| ^^^^^ expected expression
|
| ^^^ expected one of `move`, `|`, or `||` here
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ pub fn check_async() {
|
|||||||
r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
|
r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
|
||||||
r#async = consumes_async_raw!(r#async); // OK
|
r#async = consumes_async_raw!(r#async); // OK
|
||||||
|
|
||||||
if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
|
if passes_ident!(async) == 1 {}
|
||||||
if passes_ident!(r#async) == 1 {} // OK
|
if passes_ident!(r#async) == 1 {} // OK
|
||||||
module::async(); //~ ERROR expected identifier, found reserved keyword `async`
|
module::async(); //~ ERROR expected identifier, found reserved keyword `async`
|
||||||
module::r#async(); // OK
|
module::r#async(); // OK
|
||||||
|
@ -22,11 +22,11 @@ error: no rules expected the token `async`
|
|||||||
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: expected expression, found reserved keyword `async`
|
error: expected one of `move`, `|`, or `||`, found `<eof>`
|
||||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:28:22
|
--> <passes_ident macros>:1:22
|
||||||
|
|
|
|
||||||
LL | if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
|
LL | ( $ i : ident ) => ( $ i )
|
||||||
| ^^^^^ expected expression
|
| ^^^ expected one of `move`, `|`, or `||` here
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
20
src/test/ui/feature-gate-async-await-2015-edition.rs
Normal file
20
src/test/ui/feature-gate-async-await-2015-edition.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: --edition=2015
|
||||||
|
|
||||||
|
#![feature(futures_api)]
|
||||||
|
|
||||||
|
async fn foo() {} //~ ERROR async fn is unstable
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = async {}; //~ ERROR cannot find struct, variant or union type `async`
|
||||||
|
let _ = async || {}; //~ ERROR cannot find value `async` in this scope
|
||||||
|
}
|
24
src/test/ui/feature-gate-async-await-2015-edition.stderr
Normal file
24
src/test/ui/feature-gate-async-await-2015-edition.stderr
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
error[E0422]: cannot find struct, variant or union type `async` in this scope
|
||||||
|
--> $DIR/feature-gate-async-await-2015-edition.rs:18:13
|
||||||
|
|
|
||||||
|
LL | let _ = async {}; //~ ERROR cannot find struct, variant or union type `async`
|
||||||
|
| ^^^^^ not found in this scope
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `async` in this scope
|
||||||
|
--> $DIR/feature-gate-async-await-2015-edition.rs:19:13
|
||||||
|
|
|
||||||
|
LL | let _ = async || {}; //~ ERROR cannot find value `async` in this scope
|
||||||
|
| ^^^^^ not found in this scope
|
||||||
|
|
||||||
|
error[E0658]: async fn is unstable (see issue #50547)
|
||||||
|
--> $DIR/feature-gate-async-await-2015-edition.rs:15:1
|
||||||
|
|
|
||||||
|
LL | async fn foo() {} //~ ERROR async fn is unstable
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(async_await)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors occurred: E0422, E0425, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0422`.
|
19
src/test/ui/feature-gate-async-await.rs
Normal file
19
src/test/ui/feature-gate-async-await.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: --edition=2018
|
||||||
|
#![feature(futures_api)]
|
||||||
|
|
||||||
|
async fn foo() {} //~ ERROR async fn is unstable
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = async {}; //~ ERROR async blocks are unstable
|
||||||
|
let _ = async || {}; //~ ERROR async closures are unstable
|
||||||
|
}
|
27
src/test/ui/feature-gate-async-await.stderr
Normal file
27
src/test/ui/feature-gate-async-await.stderr
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
error[E0658]: async fn is unstable (see issue #50547)
|
||||||
|
--> $DIR/feature-gate-async-await.rs:14:1
|
||||||
|
|
|
||||||
|
LL | async fn foo() {} //~ ERROR async fn is unstable
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(async_await)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: async blocks are unstable (see issue #50547)
|
||||||
|
--> $DIR/feature-gate-async-await.rs:17:13
|
||||||
|
|
|
||||||
|
LL | let _ = async {}; //~ ERROR async blocks are unstable
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(async_await)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: async closures are unstable (see issue #50547)
|
||||||
|
--> $DIR/feature-gate-async-await.rs:18:13
|
||||||
|
|
|
||||||
|
LL | let _ = async || {}; //~ ERROR async closures are unstable
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(async_await)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
18
src/test/ui/no-args-non-move-async-closure.rs
Normal file
18
src/test/ui/no-args-non-move-async-closure.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: --edition=2018
|
||||||
|
|
||||||
|
#![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = async |x: u8| {};
|
||||||
|
//~^ ERROR `async` non-`move` closures with arguments are not currently supported
|
||||||
|
}
|
11
src/test/ui/no-args-non-move-async-closure.stderr
Normal file
11
src/test/ui/no-args-non-move-async-closure.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error[E0705]: `async` non-`move` closures with arguments are not currently supported
|
||||||
|
--> $DIR/no-args-non-move-async-closure.rs:16:13
|
||||||
|
|
|
||||||
|
LL | let _ = async |x: u8| {};
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using `let` statements to manually capture variables by reference before entering an `async move` closure
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0705`.
|
Loading…
Reference in New Issue
Block a user