Auto merge of #51580 - cramertj:async-await, r=eddyb
async/await This PR implements `async`/`await` syntax for `async fn` in Rust 2015 and `async` closures and `async` blocks in Rust 2018 (tracking issue: https://github.com/rust-lang/rust/issues/50547). Limitations: non-`move` async closures with arguments are currently not supported, nor are `async fn` with multiple different input lifetimes. These limitations are not fundamental and will be removed in the future, however I'd like to go ahead and get this PR merged so we can start experimenting with this in combination with futures 0.3. Based on https://github.com/rust-lang/rust/pull/51414. cc @petrochenkov for parsing changes. r? @eddyb
This commit is contained in:
commit
56e8f29dbe
69 changed files with 1796 additions and 538 deletions
|
@ -2131,5 +2131,10 @@ register_diagnostics! {
|
|||
E0657, // `impl Trait` can only capture lifetimes bound at the fn level
|
||||
E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
|
||||
E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
|
||||
E0697, // closures cannot be static
|
||||
|
||||
E0906, // closures cannot be static
|
||||
|
||||
E0725, // multiple different lifetimes used in arguments of `async fn`
|
||||
E0726, // multiple elided lifetimes used in arguments of `async fn`
|
||||
E0727, // `async` non-`move` closures with arguments are not currently supported
|
||||
}
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
//! This order consistency is required in a few places in rustc, for
|
||||
//! example generator inference, and possibly also HIR borrowck.
|
||||
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::ast::{NodeId, CRATE_NODE_ID, Ident, Name, Attribute};
|
||||
use syntax_pos::Span;
|
||||
use hir::*;
|
||||
|
@ -54,8 +53,8 @@ use std::u32;
|
|||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum FnKind<'a> {
|
||||
/// fn foo() or extern "Abi" fn foo()
|
||||
ItemFn(Name, &'a Generics, Unsafety, Constness, Abi, &'a Visibility, &'a [Attribute]),
|
||||
/// #[xxx] pub async/const/extern "Abi" fn foo()
|
||||
ItemFn(Name, &'a Generics, FnHeader, &'a Visibility, &'a [Attribute]),
|
||||
|
||||
/// fn foo(&self)
|
||||
Method(Name, &'a MethodSig, Option<&'a Visibility>, &'a [Attribute]),
|
||||
|
@ -479,12 +478,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
|
|||
visitor.visit_ty(typ);
|
||||
visitor.visit_nested_body(body);
|
||||
}
|
||||
ItemFn(ref declaration, unsafety, constness, abi, ref generics, body_id) => {
|
||||
ItemFn(ref declaration, header, ref generics, body_id) => {
|
||||
visitor.visit_fn(FnKind::ItemFn(item.name,
|
||||
generics,
|
||||
unsafety,
|
||||
constness,
|
||||
abi,
|
||||
header,
|
||||
&item.vis,
|
||||
&item.attrs),
|
||||
declaration,
|
||||
|
|
|
@ -168,6 +168,7 @@ pub trait Resolver {
|
|||
span: Span,
|
||||
crate_root: Option<&str>,
|
||||
components: &[&str],
|
||||
params: Option<P<hir::GenericArgs>>,
|
||||
is_value: bool,
|
||||
) -> hir::Path;
|
||||
}
|
||||
|
@ -449,7 +450,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() {
|
||||
bug!(
|
||||
"Tried to allocate item_local_id_counter for {:?} twice",
|
||||
|
@ -457,7 +458,7 @@ impl<'a> LoweringContext<'a> {
|
|||
);
|
||||
}
|
||||
// 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
|
||||
|
@ -501,7 +502,7 @@ impl<'a> LoweringContext<'a> {
|
|||
{
|
||||
let counter = self.item_local_id_counters
|
||||
.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();
|
||||
self.current_hir_id_owner.push((def_index, counter));
|
||||
let ret = f(self);
|
||||
|
@ -840,6 +841,46 @@ impl<'a> LoweringContext<'a> {
|
|||
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, &["future", "from_generator"], None, ThinVec::new());
|
||||
hir::ExprCall(P(gen_future), hir_vec![generator])
|
||||
}
|
||||
|
||||
fn lower_body<F>(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId
|
||||
where
|
||||
F: FnOnce(&mut LoweringContext) -> hir::Expr,
|
||||
|
@ -1067,7 +1108,7 @@ impl<'a> LoweringContext<'a> {
|
|||
),
|
||||
unsafety: this.lower_unsafety(f.unsafety),
|
||||
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),
|
||||
}))
|
||||
},
|
||||
|
@ -1132,92 +1173,8 @@ impl<'a> LoweringContext<'a> {
|
|||
let span = t.span;
|
||||
match itctx {
|
||||
ImplTraitContext::Existential(fn_def_id) => {
|
||||
|
||||
// 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,
|
||||
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,
|
||||
)
|
||||
})
|
||||
self.lower_existential_impl_trait(
|
||||
span, fn_def_id, |this| this.lower_param_bounds(bounds, itctx))
|
||||
}
|
||||
ImplTraitContext::Universal(def_id) => {
|
||||
let def_node_id = self.next_id().node_id;
|
||||
|
@ -1281,6 +1238,94 @@ impl<'a> LoweringContext<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn lower_existential_impl_trait(
|
||||
&mut self,
|
||||
span: Span,
|
||||
fn_def_id: DefId,
|
||||
lower_bounds: impl FnOnce(&mut LoweringContext) -> hir::GenericBounds,
|
||||
) -> 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: keywords::Invalid.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(
|
||||
&mut self,
|
||||
exist_ty_id: NodeId,
|
||||
|
@ -1829,21 +1874,25 @@ impl<'a> LoweringContext<'a> {
|
|||
.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(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
fn_def_id: Option<DefId>,
|
||||
impl_trait_return_allow: bool,
|
||||
make_ret_async: bool,
|
||||
) -> P<hir::FnDecl> {
|
||||
// NOTE: The two last parameters here have to do with impl Trait. If fn_def_id is Some,
|
||||
// then impl Trait arguments are lowered into generic parameters on the given
|
||||
// fn_def_id, otherwise impl Trait is disallowed. (for now)
|
||||
//
|
||||
// Furthermore, if impl_trait_return_allow is true, then impl Trait may be used in
|
||||
// return positions as well. This guards against trait declarations and their impls
|
||||
// where impl Trait is disallowed. (again for now)
|
||||
P(hir::FnDecl {
|
||||
inputs: decl.inputs
|
||||
let inputs = decl.inputs
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
if let Some(def_id) = fn_def_id {
|
||||
|
@ -1852,8 +1901,13 @@ impl<'a> LoweringContext<'a> {
|
|||
self.lower_ty(&arg.ty, ImplTraitContext::Disallowed)
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
output: match decl.output {
|
||||
.collect::<HirVec<_>>();
|
||||
|
||||
let output = if make_ret_async {
|
||||
self.lower_async_fn_ret_ty(
|
||||
&inputs, &decl.output, fn_def_id.expect("make_ret_async but no fn_def_id"))
|
||||
} else {
|
||||
match decl.output {
|
||||
FunctionRetTy::Ty(ref ty) => match fn_def_id {
|
||||
Some(def_id) if impl_trait_return_allow => {
|
||||
hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(def_id)))
|
||||
|
@ -1861,7 +1915,12 @@ impl<'a> LoweringContext<'a> {
|
|||
_ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
|
||||
},
|
||||
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
P(hir::FnDecl {
|
||||
inputs,
|
||||
output,
|
||||
variadic: decl.variadic,
|
||||
has_implicit_self: decl.inputs.get(0).map_or(false, |arg| match arg.ty.node {
|
||||
TyKind::ImplicitSelf => true,
|
||||
|
@ -1871,6 +1930,231 @@ 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_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs) {
|
||||
// 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_generic_args(self, span, parameters);
|
||||
self.collect_elided_lifetimes = old_collect_elided_lifetimes;
|
||||
} else {
|
||||
hir::intravisit::walk_generic_args(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::GenericParamKind::Lifetime { .. } = param.kind {
|
||||
// Introduce lifetimes one at a time so that we can handle
|
||||
// cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`
|
||||
let lt_name = hir::LifetimeName::Param(param.name);
|
||||
self.currently_bound_lifetimes.push(lt_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;
|
||||
}
|
||||
}
|
||||
hir::LifetimeName::Param(_) => lifetime.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),
|
||||
E0725,
|
||||
"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 \
|
||||
with 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),
|
||||
E0726,
|
||||
"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 span = match output {
|
||||
FunctionRetTy::Ty(ty) => ty.span,
|
||||
FunctionRetTy::Default(span) => *span,
|
||||
};
|
||||
|
||||
let impl_trait_ty = self.lower_existential_impl_trait(
|
||||
span, fn_def_id, |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,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// "<Output = T>"
|
||||
let future_params = P(hir::GenericArgs {
|
||||
args: 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,
|
||||
});
|
||||
|
||||
let future_path =
|
||||
this.std_path(span, &["future", "Future"], Some(future_params), false);
|
||||
|
||||
let mut bounds = vec![
|
||||
hir::GenericBound::Trait(
|
||||
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::GenericBound::Outlives(
|
||||
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(
|
||||
&mut self,
|
||||
tpb: &GenericBound,
|
||||
|
@ -2284,25 +2568,40 @@ impl<'a> LoweringContext<'a> {
|
|||
let value = self.lower_body(None, |this| this.lower_expr(e));
|
||||
hir::ItemConst(self.lower_ty(t, ImplTraitContext::Disallowed), value)
|
||||
}
|
||||
ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
|
||||
ItemKind::Fn(ref decl, header, ref generics, ref body) => {
|
||||
let fn_def_id = self.resolver.definitions().local_def_id(id);
|
||||
|
||||
self.with_new_scopes(|this| {
|
||||
// Note: we don't need to change the return type from `T` to
|
||||
// `impl Future<Output = T>` here because lower_body
|
||||
// only cares about the input argument patterns in the function
|
||||
// declaration (decl), not the return types.
|
||||
let body_id = this.lower_body(Some(decl), |this| {
|
||||
if let IsAsync::Async(async_node_id) = header.asyncness {
|
||||
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(
|
||||
generics,
|
||||
fn_def_id,
|
||||
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(
|
||||
fn_decl,
|
||||
this.lower_unsafety(unsafety),
|
||||
this.lower_constness(constness),
|
||||
abi,
|
||||
this.lower_fn_header(header),
|
||||
generics,
|
||||
body_id,
|
||||
)
|
||||
|
@ -2620,7 +2919,7 @@ impl<'a> LoweringContext<'a> {
|
|||
AnonymousLifetimeMode::PassThrough,
|
||||
|this| {
|
||||
hir::TraitItemKind::Method(
|
||||
this.lower_method_sig(sig, trait_item_def_id, false),
|
||||
this.lower_method_sig(sig, trait_item_def_id, false, false),
|
||||
hir::TraitMethod::Required(names),
|
||||
)
|
||||
},
|
||||
|
@ -2638,7 +2937,7 @@ impl<'a> LoweringContext<'a> {
|
|||
AnonymousLifetimeMode::PassThrough,
|
||||
|this| {
|
||||
hir::TraitItemKind::Method(
|
||||
this.lower_method_sig(sig, trait_item_def_id, false),
|
||||
this.lower_method_sig(sig, trait_item_def_id, false, false),
|
||||
hir::TraitMethod::Provided(body_id),
|
||||
)
|
||||
},
|
||||
|
@ -2709,9 +3008,19 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
ImplItemKind::Method(ref sig, ref body) => {
|
||||
let body_id = self.lower_body(Some(&sig.decl), |this| {
|
||||
if let IsAsync::Async(async_node_id) = sig.header.asyncness {
|
||||
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 impl_trait_return_allow = !self.is_in_trait_impl;
|
||||
|
||||
self.add_in_band_defs(
|
||||
|
@ -2724,6 +3033,7 @@ impl<'a> LoweringContext<'a> {
|
|||
sig,
|
||||
impl_item_def_id,
|
||||
impl_trait_return_allow,
|
||||
sig.header.asyncness.is_async(),
|
||||
),
|
||||
body_id,
|
||||
)
|
||||
|
@ -2865,7 +3175,7 @@ impl<'a> LoweringContext<'a> {
|
|||
|this| {
|
||||
(
|
||||
// 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),
|
||||
)
|
||||
},
|
||||
|
@ -2889,12 +3199,11 @@ impl<'a> LoweringContext<'a> {
|
|||
sig: &MethodSig,
|
||||
fn_def_id: DefId,
|
||||
impl_trait_return_allow: bool,
|
||||
is_async: bool,
|
||||
) -> hir::MethodSig {
|
||||
hir::MethodSig {
|
||||
abi: sig.abi,
|
||||
unsafety: self.lower_unsafety(sig.unsafety),
|
||||
constness: self.lower_constness(sig.constness),
|
||||
decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow),
|
||||
header: self.lower_fn_header(sig.header),
|
||||
decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow, is_async),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2905,6 +3214,15 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
|
||||
hir::FnHeader {
|
||||
unsafety: self.lower_unsafety(h.unsafety),
|
||||
asyncness: self.lower_asyncness(h.asyncness),
|
||||
constness: self.lower_constness(h.constness),
|
||||
abi: h.abi,
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
|
||||
match u {
|
||||
Unsafety::Unsafe => hir::Unsafety::Unsafe,
|
||||
|
@ -2919,6 +3237,13 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync {
|
||||
match a {
|
||||
IsAsync::Async(_) => hir::IsAsync::Async,
|
||||
IsAsync::NotAsync => hir::IsAsync::NotAsync,
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
|
||||
match u {
|
||||
UnOp::Deref => hir::UnDeref,
|
||||
|
@ -3206,8 +3531,62 @@ impl<'a> LoweringContext<'a> {
|
|||
arms.iter().map(|x| self.lower_arm(x)).collect(),
|
||||
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| {
|
||||
if let IsAsync::Async(async_closure_node_id) = asyncness {
|
||||
// FIXME(cramertj) allow `async` non-`move` closures with
|
||||
if capture_clause == CaptureBy::Ref &&
|
||||
!decl.inputs.is_empty()
|
||||
{
|
||||
struct_span_err!(
|
||||
this.sess,
|
||||
fn_decl_span,
|
||||
E0727,
|
||||
"`async` non-`move` closures with arguments \
|
||||
are not currently supported",
|
||||
)
|
||||
.help("consider using `let` statements to manually capture \
|
||||
variables by reference before entering an \
|
||||
`async move` closure")
|
||||
.emit();
|
||||
}
|
||||
|
||||
// Transform `async |x: u8| -> X { ... }` into
|
||||
// `|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 {
|
||||
let mut is_generator = false;
|
||||
let body_id = this.lower_body(Some(decl), |this| {
|
||||
let e = this.lower_expr(body);
|
||||
|
@ -3233,7 +3612,7 @@ impl<'a> LoweringContext<'a> {
|
|||
span_err!(
|
||||
this.sess,
|
||||
fn_decl_span,
|
||||
E0697,
|
||||
E0906,
|
||||
"closures cannot be static"
|
||||
);
|
||||
}
|
||||
|
@ -3241,11 +3620,12 @@ impl<'a> LoweringContext<'a> {
|
|||
};
|
||||
hir::ExprClosure(
|
||||
this.lower_capture_clause(capture_clause),
|
||||
this.lower_fn_decl(decl, None, false),
|
||||
this.lower_fn_decl(decl, None, false, false),
|
||||
body_id,
|
||||
fn_decl_span,
|
||||
generator_option,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
ExprKind::Block(ref blk, opt_label) => {
|
||||
|
@ -3272,7 +3652,7 @@ impl<'a> LoweringContext<'a> {
|
|||
let id = self.next_id();
|
||||
let e1 = self.lower_expr(e1);
|
||||
let e2 = self.lower_expr(e2);
|
||||
let ty_path = P(self.std_path(span, &["ops", "RangeInclusive"], false));
|
||||
let ty_path = P(self.std_path(span, &["ops", "RangeInclusive"], None, false));
|
||||
let ty = self.ty_path(id, span, hir::QPath::Resolved(None, ty_path));
|
||||
let new_seg = P(hir::PathSegment::from_name(Symbol::intern("new")));
|
||||
let new_path = hir::QPath::TypeRelative(ty, new_seg);
|
||||
|
@ -3312,7 +3692,7 @@ impl<'a> LoweringContext<'a> {
|
|||
let struct_path = iter::once("ops")
|
||||
.chain(iter::once(path))
|
||||
.collect::<Vec<_>>();
|
||||
let struct_path = self.std_path(unstable_span, &struct_path, is_unit);
|
||||
let struct_path = self.std_path(unstable_span, &struct_path, None, is_unit);
|
||||
let struct_path = hir::QPath::Resolved(None, P(struct_path));
|
||||
|
||||
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id);
|
||||
|
@ -3589,7 +3969,7 @@ impl<'a> LoweringContext<'a> {
|
|||
let iter = P(self.expr_ident(head_sp, iter, iter_pat.id));
|
||||
let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
|
||||
let next_path = &["iter", "Iterator", "next"];
|
||||
let next_path = P(self.expr_std_path(head_sp, next_path, ThinVec::new()));
|
||||
let next_path = P(self.expr_std_path(head_sp, next_path, None, ThinVec::new()));
|
||||
let next_expr = P(self.expr_call(head_sp, next_path, hir_vec![ref_mut_iter]));
|
||||
let arms = hir_vec![pat_arm, break_arm];
|
||||
|
||||
|
@ -3647,7 +4027,8 @@ impl<'a> LoweringContext<'a> {
|
|||
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
|
||||
let into_iter_expr = {
|
||||
let into_iter_path = &["iter", "IntoIterator", "into_iter"];
|
||||
let into_iter = P(self.expr_std_path(head_sp, into_iter_path, ThinVec::new()));
|
||||
let into_iter = P(self.expr_std_path(
|
||||
head_sp, into_iter_path, None, ThinVec::new()));
|
||||
P(self.expr_call(head_sp, into_iter, hir_vec![head]))
|
||||
};
|
||||
|
||||
|
@ -3693,7 +4074,8 @@ impl<'a> LoweringContext<'a> {
|
|||
let sub_expr = self.lower_expr(sub_expr);
|
||||
|
||||
let path = &["ops", "Try", "into_result"];
|
||||
let path = P(self.expr_std_path(unstable_span, path, ThinVec::new()));
|
||||
let path = P(self.expr_std_path(
|
||||
unstable_span, path, None, ThinVec::new()));
|
||||
P(self.expr_call(e.span, path, hir_vec![sub_expr]))
|
||||
};
|
||||
|
||||
|
@ -3732,7 +4114,8 @@ impl<'a> LoweringContext<'a> {
|
|||
let err_local = self.pat_ident(e.span, err_ident);
|
||||
let from_expr = {
|
||||
let path = &["convert", "From", "from"];
|
||||
let from = P(self.expr_std_path(e.span, path, ThinVec::new()));
|
||||
let from = P(self.expr_std_path(
|
||||
e.span, path, None, ThinVec::new()));
|
||||
let err_expr = self.expr_ident(e.span, err_ident, err_local.id);
|
||||
|
||||
self.expr_call(e.span, from, hir_vec![err_expr])
|
||||
|
@ -3972,9 +4355,10 @@ impl<'a> LoweringContext<'a> {
|
|||
&mut self,
|
||||
span: Span,
|
||||
components: &[&str],
|
||||
params: Option<P<hir::GenericArgs>>,
|
||||
attrs: ThinVec<Attribute>,
|
||||
) -> hir::Expr {
|
||||
let path = self.std_path(span, components, true);
|
||||
let path = self.std_path(span, components, params, true);
|
||||
self.expr(
|
||||
span,
|
||||
hir::ExprPath(hir::QPath::Resolved(None, P(path))),
|
||||
|
@ -4099,7 +4483,7 @@ impl<'a> LoweringContext<'a> {
|
|||
components: &[&str],
|
||||
subpats: hir::HirVec<P<hir::Pat>>,
|
||||
) -> P<hir::Pat> {
|
||||
let path = self.std_path(span, components, true);
|
||||
let path = self.std_path(span, components, None, true);
|
||||
let qpath = hir::QPath::Resolved(None, P(path));
|
||||
let pt = if subpats.is_empty() {
|
||||
hir::PatKind::Path(qpath)
|
||||
|
@ -4146,9 +4530,15 @@ impl<'a> LoweringContext<'a> {
|
|||
/// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
|
||||
/// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
|
||||
/// The path is also resolved according to `is_value`.
|
||||
fn std_path(&mut self, span: Span, components: &[&str], is_value: bool) -> hir::Path {
|
||||
fn std_path(
|
||||
&mut self,
|
||||
span: Span,
|
||||
components: &[&str],
|
||||
params: Option<P<hir::GenericArgs>>,
|
||||
is_value: bool
|
||||
) -> hir::Path {
|
||||
self.resolver
|
||||
.resolve_str_path(span, self.crate_root, components, is_value)
|
||||
.resolve_str_path(span, self.crate_root, components, params, is_value)
|
||||
}
|
||||
|
||||
fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> P<hir::Ty> {
|
||||
|
@ -4280,7 +4670,7 @@ impl<'a> LoweringContext<'a> {
|
|||
unstable_span: Span,
|
||||
) -> P<hir::Expr> {
|
||||
let path = &["ops", "Try", method];
|
||||
let from_err = P(self.expr_std_path(unstable_span, path,
|
||||
let from_err = P(self.expr_std_path(unstable_span, path, None,
|
||||
ThinVec::new()));
|
||||
P(self.expr_call(e.span, from_err, hir_vec![e]))
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ use hir as ast;
|
|||
use hir::map::{self, Node};
|
||||
use hir::{Expr, FnDecl};
|
||||
use hir::intravisit::FnKind;
|
||||
use rustc_target::spec::abi;
|
||||
use syntax::ast::{Attribute, Name, NodeId};
|
||||
use syntax_pos::Span;
|
||||
|
||||
|
@ -105,9 +104,7 @@ impl<'a> Code<'a> {
|
|||
struct ItemFnParts<'a> {
|
||||
name: Name,
|
||||
decl: &'a ast::FnDecl,
|
||||
unsafety: ast::Unsafety,
|
||||
constness: ast::Constness,
|
||||
abi: abi::Abi,
|
||||
header: ast::FnHeader,
|
||||
vis: &'a ast::Visibility,
|
||||
generics: &'a ast::Generics,
|
||||
body: ast::BodyId,
|
||||
|
@ -183,31 +180,31 @@ impl<'a> FnLikeNode<'a> {
|
|||
|
||||
pub fn constness(self) -> ast::Constness {
|
||||
match self.kind() {
|
||||
FnKind::ItemFn(_, _, _, constness, ..) => {
|
||||
constness
|
||||
}
|
||||
FnKind::Method(_, m, ..) => {
|
||||
m.constness
|
||||
}
|
||||
FnKind::ItemFn(_, _, header, ..) => header.constness,
|
||||
FnKind::Method(_, m, ..) => m.header.constness,
|
||||
_ => ast::Constness::NotConst
|
||||
}
|
||||
}
|
||||
|
||||
pub fn asyncness(self) -> ast::IsAsync {
|
||||
match self.kind() {
|
||||
FnKind::ItemFn(_, _, header, ..) => header.asyncness,
|
||||
FnKind::Method(_, m, ..) => m.header.asyncness,
|
||||
_ => ast::IsAsync::NotAsync
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unsafety(self) -> ast::Unsafety {
|
||||
match self.kind() {
|
||||
FnKind::ItemFn(_, _, unsafety, ..) => {
|
||||
unsafety
|
||||
}
|
||||
FnKind::Method(_, m, ..) => {
|
||||
m.unsafety
|
||||
}
|
||||
FnKind::ItemFn(_, _, header, ..) => header.unsafety,
|
||||
FnKind::Method(_, m, ..) => m.header.unsafety,
|
||||
_ => ast::Unsafety::Normal
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kind(self) -> FnKind<'a> {
|
||||
let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
|
||||
FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis, p.attrs)
|
||||
FnKind::ItemFn(p.name, p.generics, p.header, p.vis, p.attrs)
|
||||
};
|
||||
let closure = |c: ClosureParts<'a>| {
|
||||
FnKind::Closure(c.attrs)
|
||||
|
@ -232,19 +229,17 @@ impl<'a> FnLikeNode<'a> {
|
|||
{
|
||||
match self.node {
|
||||
map::NodeItem(i) => match i.node {
|
||||
ast::ItemFn(ref decl, unsafety, constness, abi, ref generics, block) =>
|
||||
ast::ItemFn(ref decl, header, ref generics, block) =>
|
||||
item_fn(ItemFnParts {
|
||||
id: i.id,
|
||||
name: i.name,
|
||||
decl: &decl,
|
||||
unsafety,
|
||||
body: block,
|
||||
generics,
|
||||
abi,
|
||||
vis: &i.vis,
|
||||
constness,
|
||||
span: i.span,
|
||||
attrs: &i.attrs,
|
||||
header,
|
||||
generics,
|
||||
}),
|
||||
_ => bug!("item FnLikeNode that is not fn-like"),
|
||||
},
|
||||
|
|
|
@ -73,6 +73,27 @@ impl<'a> DefCollector<'a> {
|
|||
self.parent_def = parent;
|
||||
}
|
||||
|
||||
fn visit_async_fn(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
async_node_id: NodeId,
|
||||
name: Name,
|
||||
span: Span,
|
||||
visit_fn: impl FnOnce(&mut DefCollector<'a>)
|
||||
) {
|
||||
// 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(name.as_interned_str());
|
||||
let fn_def = self.create_def(id, fn_def_data, ITEM_LIKE_SPACE, span);
|
||||
return self.with_parent(fn_def, |this| {
|
||||
let closure_def = this.create_def(async_node_id,
|
||||
DefPathData::ClosureExpr,
|
||||
REGULAR_SPACE,
|
||||
span);
|
||||
this.with_parent(closure_def, visit_fn)
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_macro_invoc(&mut self, id: NodeId) {
|
||||
if let Some(ref mut visit) = self.visit_macro_invoc {
|
||||
visit(MacroInvocationData {
|
||||
|
@ -99,6 +120,15 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
|
||||
return visit::walk_item(self, i);
|
||||
}
|
||||
ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, ..) => {
|
||||
return self.visit_async_fn(
|
||||
i.id,
|
||||
async_node_id,
|
||||
i.ident.name,
|
||||
i.span,
|
||||
|this| visit::walk_item(this, i)
|
||||
)
|
||||
}
|
||||
ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_interned_str()),
|
||||
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
|
||||
DefPathData::ValueNs(i.ident.name.as_interned_str()),
|
||||
|
@ -197,6 +227,17 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
|
||||
fn visit_impl_item(&mut self, ii: &'a ImplItem) {
|
||||
let def_data = match ii.node {
|
||||
ImplItemKind::Method(MethodSig {
|
||||
header: FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, ..
|
||||
}, ..) => {
|
||||
return self.visit_async_fn(
|
||||
ii.id,
|
||||
async_node_id,
|
||||
ii.ident.name,
|
||||
ii.span,
|
||||
|this| visit::walk_impl_item(this, ii)
|
||||
)
|
||||
}
|
||||
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
|
||||
DefPathData::ValueNs(ii.ident.name.as_interned_str()),
|
||||
ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.name.as_interned_str()),
|
||||
|
@ -227,15 +268,32 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
|
||||
match expr.node {
|
||||
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id),
|
||||
ExprKind::Closure(..) => {
|
||||
let def = self.create_def(expr.id,
|
||||
ExprKind::Closure(_, asyncness, ..) => {
|
||||
let closure_def = self.create_def(expr.id,
|
||||
DefPathData::ClosureExpr,
|
||||
REGULAR_SPACE,
|
||||
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);
|
||||
self.parent_def = parent_def;
|
||||
|
|
|
@ -174,7 +174,7 @@ impl<'hir> MapEntry<'hir> {
|
|||
match self {
|
||||
EntryItem(_, _, ref item) => {
|
||||
match item.node {
|
||||
ItemFn(ref fn_decl, _, _, _, _, _) => Some(&fn_decl),
|
||||
ItemFn(ref fn_decl, _, _, _) => Some(&fn_decl),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ impl<'hir> MapEntry<'hir> {
|
|||
match item.node {
|
||||
ItemConst(_, body) |
|
||||
ItemStatic(.., body) |
|
||||
ItemFn(_, _, _, _, _, body) => Some(body),
|
||||
ItemFn(_, _, _, body) => Some(body),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -255,7 +255,7 @@ impl LifetimeName {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_elided(&self) -> bool {
|
||||
pub fn is_elided(&self) -> bool {
|
||||
use self::LifetimeName::*;
|
||||
match self {
|
||||
Implicit | Underscore => true,
|
||||
|
@ -1506,9 +1506,7 @@ pub struct MutTy {
|
|||
/// Represents a method's signature in a trait declaration or implementation.
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub struct MethodSig {
|
||||
pub unsafety: Unsafety,
|
||||
pub constness: Constness,
|
||||
pub abi: Abi,
|
||||
pub header: FnHeader,
|
||||
pub decl: P<FnDecl>,
|
||||
}
|
||||
|
||||
|
@ -1736,7 +1734,13 @@ pub enum IsAuto {
|
|||
No
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq,PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum IsAsync {
|
||||
Async,
|
||||
NotAsync,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum Unsafety {
|
||||
Unsafe,
|
||||
Normal,
|
||||
|
@ -2012,6 +2016,14 @@ pub struct Item {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub struct FnHeader {
|
||||
pub unsafety: Unsafety,
|
||||
pub constness: Constness,
|
||||
pub asyncness: IsAsync,
|
||||
pub abi: Abi,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum Item_ {
|
||||
/// An `extern crate` item, with optional *original* crate name if the crate was renamed.
|
||||
|
@ -2031,7 +2043,7 @@ pub enum Item_ {
|
|||
/// A `const` item
|
||||
ItemConst(P<Ty>, BodyId),
|
||||
/// A function declaration
|
||||
ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, BodyId),
|
||||
ItemFn(P<FnDecl>, FnHeader, Generics, BodyId),
|
||||
/// A module
|
||||
ItemMod(Mod),
|
||||
/// An external module
|
||||
|
@ -2096,7 +2108,7 @@ impl Item_ {
|
|||
|
||||
pub fn generics(&self) -> Option<&Generics> {
|
||||
Some(match *self {
|
||||
ItemFn(_, _, _, _, ref generics, _) |
|
||||
ItemFn(_, _, ref generics, _) |
|
||||
ItemTy(_, ref generics) |
|
||||
ItemEnum(_, ref generics) |
|
||||
ItemStruct(_, ref generics) |
|
||||
|
|
|
@ -459,9 +459,12 @@ impl<'a> State<'a> {
|
|||
hir::ForeignItemFn(ref decl, ref arg_names, ref generics) => {
|
||||
self.head("")?;
|
||||
self.print_fn(decl,
|
||||
hir::Unsafety::Normal,
|
||||
hir::Constness::NotConst,
|
||||
Abi::Rust,
|
||||
hir::FnHeader {
|
||||
unsafety: hir::Unsafety::Normal,
|
||||
constness: hir::Constness::NotConst,
|
||||
abi: Abi::Rust,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
},
|
||||
Some(item.name),
|
||||
generics,
|
||||
&item.vis,
|
||||
|
@ -598,12 +601,10 @@ impl<'a> State<'a> {
|
|||
self.s.word(";")?;
|
||||
self.end()?; // end the outer cbox
|
||||
}
|
||||
hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, body) => {
|
||||
hir::ItemFn(ref decl, header, ref typarams, body) => {
|
||||
self.head("")?;
|
||||
self.print_fn(decl,
|
||||
unsafety,
|
||||
constness,
|
||||
abi,
|
||||
header,
|
||||
Some(item.name),
|
||||
typarams,
|
||||
&item.vis,
|
||||
|
@ -935,9 +936,7 @@ impl<'a> State<'a> {
|
|||
body_id: Option<hir::BodyId>)
|
||||
-> io::Result<()> {
|
||||
self.print_fn(&m.decl,
|
||||
m.unsafety,
|
||||
m.constness,
|
||||
m.abi,
|
||||
m.header,
|
||||
Some(name),
|
||||
generics,
|
||||
vis,
|
||||
|
@ -1986,16 +1985,14 @@ impl<'a> State<'a> {
|
|||
|
||||
pub fn print_fn(&mut self,
|
||||
decl: &hir::FnDecl,
|
||||
unsafety: hir::Unsafety,
|
||||
constness: hir::Constness,
|
||||
abi: Abi,
|
||||
header: hir::FnHeader,
|
||||
name: Option<ast::Name>,
|
||||
generics: &hir::Generics,
|
||||
vis: &hir::Visibility,
|
||||
arg_names: &[Spanned<ast::Name>],
|
||||
body_id: Option<hir::BodyId>)
|
||||
-> io::Result<()> {
|
||||
self.print_fn_header_info(unsafety, constness, abi, vis)?;
|
||||
self.print_fn_header_info(header, vis)?;
|
||||
|
||||
if let Some(name) = name {
|
||||
self.nbsp()?;
|
||||
|
@ -2260,9 +2257,12 @@ impl<'a> State<'a> {
|
|||
span: syntax_pos::DUMMY_SP,
|
||||
};
|
||||
self.print_fn(decl,
|
||||
hir::FnHeader {
|
||||
unsafety,
|
||||
hir::Constness::NotConst,
|
||||
abi,
|
||||
constness: hir::Constness::NotConst,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
},
|
||||
name,
|
||||
&generics,
|
||||
&hir::Inherited,
|
||||
|
@ -2333,22 +2333,26 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
pub fn print_fn_header_info(&mut self,
|
||||
unsafety: hir::Unsafety,
|
||||
constness: hir::Constness,
|
||||
abi: Abi,
|
||||
header: hir::FnHeader,
|
||||
vis: &hir::Visibility)
|
||||
-> io::Result<()> {
|
||||
self.s.word(&visibility_qualified(vis, ""))?;
|
||||
self.print_unsafety(unsafety)?;
|
||||
|
||||
match constness {
|
||||
match header.constness {
|
||||
hir::Constness::NotConst => {}
|
||||
hir::Constness::Const => self.word_nbsp("const")?,
|
||||
}
|
||||
|
||||
if abi != Abi::Rust {
|
||||
match header.asyncness {
|
||||
hir::IsAsync::NotAsync => {}
|
||||
hir::IsAsync::Async => self.word_nbsp("async")?,
|
||||
}
|
||||
|
||||
self.print_unsafety(header.unsafety)?;
|
||||
|
||||
if header.abi != Abi::Rust {
|
||||
self.word_nbsp("extern")?;
|
||||
self.word_nbsp(&abi.to_string())?;
|
||||
self.word_nbsp(&header.abi.to_string())?;
|
||||
}
|
||||
|
||||
self.s.word("fn")
|
||||
|
|
|
@ -272,9 +272,7 @@ impl_stable_hash_for!(struct hir::MutTy {
|
|||
});
|
||||
|
||||
impl_stable_hash_for!(struct hir::MethodSig {
|
||||
unsafety,
|
||||
constness,
|
||||
abi,
|
||||
header,
|
||||
decl
|
||||
});
|
||||
|
||||
|
@ -285,6 +283,13 @@ impl_stable_hash_for!(struct hir::TypeBinding {
|
|||
span
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct hir::FnHeader {
|
||||
unsafety,
|
||||
constness,
|
||||
asyncness,
|
||||
abi
|
||||
});
|
||||
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for hir::Ty {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
|
@ -897,7 +902,7 @@ impl_stable_hash_for!(enum hir::Item_ {
|
|||
ItemUse(path, use_kind),
|
||||
ItemStatic(ty, mutability, body_id),
|
||||
ItemConst(ty, body_id),
|
||||
ItemFn(fn_decl, unsafety, constness, abi, generics, body_id),
|
||||
ItemFn(fn_decl, header, generics, body_id),
|
||||
ItemMod(module),
|
||||
ItemForeignMod(foreign_mod),
|
||||
ItemGlobalAsm(global_asm),
|
||||
|
@ -1100,6 +1105,10 @@ impl_stable_hash_for!(enum hir::Unsafety {
|
|||
Normal
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum hir::IsAsync {
|
||||
Async,
|
||||
NotAsync
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum hir::Constness {
|
||||
Const,
|
||||
|
|
|
@ -409,6 +409,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat {
|
|||
});
|
||||
|
||||
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
|
||||
Async,
|
||||
DotFill,
|
||||
QuestionMark,
|
||||
ExistentialReturnType,
|
||||
|
|
|
@ -238,8 +238,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
|||
// If we are building an executable, only explicitly extern
|
||||
// types need to be exported.
|
||||
if let hir_map::NodeItem(item) = *node {
|
||||
let reachable = if let hir::ItemFn(.., abi, _, _) = item.node {
|
||||
abi != Abi::Rust
|
||||
let reachable = if let hir::ItemFn(_, header, ..) = item.node {
|
||||
header.abi != Abi::Rust
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
|
|
@ -476,7 +476,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
||||
match item.node {
|
||||
hir::ItemFn(ref decl, _, _, _, ref generics, _) => {
|
||||
hir::ItemFn(ref decl, _, ref generics, _) => {
|
||||
self.visit_early_late(None, decl, generics, |this| {
|
||||
intravisit::walk_item(this, item);
|
||||
});
|
||||
|
|
|
@ -10,12 +10,11 @@
|
|||
|
||||
use rustc::middle::allocator::AllocatorKind;
|
||||
use rustc_errors;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::ast::{Attribute, Crate, LitKind, StrStyle};
|
||||
use syntax::ast::{Arg, Constness, Generics, Mac, Mutability, Ty, Unsafety};
|
||||
use syntax::ast::{Arg, FnHeader, Generics, Mac, Mutability, Ty, Unsafety};
|
||||
use syntax::ast::{self, Expr, Ident, Item, ItemKind, TyKind, VisibilityKind};
|
||||
use syntax::attr;
|
||||
use syntax::codemap::{dummy_spanned, respan};
|
||||
use syntax::codemap::respan;
|
||||
use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan};
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
use syntax::ext::base::Resolver;
|
||||
|
@ -152,9 +151,10 @@ impl<'a> AllocFnFactory<'a> {
|
|||
let (output_ty, output_expr) = self.ret_ty(&method.output, result);
|
||||
let kind = ItemKind::Fn(
|
||||
self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)),
|
||||
Unsafety::Unsafe,
|
||||
dummy_spanned(Constness::NotConst),
|
||||
Abi::Rust,
|
||||
FnHeader {
|
||||
unsafety: Unsafety::Unsafe,
|
||||
..FnHeader::default()
|
||||
},
|
||||
Generics::default(),
|
||||
self.cx.block_expr(output_expr),
|
||||
);
|
||||
|
|
|
@ -712,8 +712,8 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
|
|||
fn fold_item_kind(&mut self, i: ast::ItemKind) -> ast::ItemKind {
|
||||
let is_const = match i {
|
||||
ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true,
|
||||
ast::ItemKind::Fn(ref decl, _, ref constness, _, _, _) =>
|
||||
constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
|
||||
ast::ItemKind::Fn(ref decl, ref header, _, _) =>
|
||||
header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
|
||||
_ => false,
|
||||
};
|
||||
self.run(is_const, |s| fold::noop_fold_item_kind(i, s))
|
||||
|
@ -722,8 +722,8 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
|
|||
fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector<ast::TraitItem> {
|
||||
let is_const = match i.node {
|
||||
ast::TraitItemKind::Const(..) => true,
|
||||
ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref constness, .. }, _) =>
|
||||
constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
|
||||
ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) =>
|
||||
header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
|
||||
_ => false,
|
||||
};
|
||||
self.run(is_const, |s| fold::noop_fold_trait_item(i, s))
|
||||
|
@ -732,8 +732,8 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
|
|||
fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector<ast::ImplItem> {
|
||||
let is_const = match i.node {
|
||||
ast::ImplItemKind::Const(..) => true,
|
||||
ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref constness, .. }, _) =>
|
||||
constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
|
||||
ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) =>
|
||||
header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
|
||||
_ => false,
|
||||
};
|
||||
self.run(is_const, |s| fold::noop_fold_impl_item(i, s))
|
||||
|
|
|
@ -284,9 +284,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
|
|||
_ => (),
|
||||
}
|
||||
}
|
||||
FnKind::ItemFn(name, _, _, _, abi, _, attrs) => {
|
||||
FnKind::ItemFn(name, _, header, _, attrs) => {
|
||||
// Skip foreign-ABI #[no_mangle] functions (Issue #31924)
|
||||
if abi != Abi::Rust && attr::find_by_name(attrs, "no_mangle").is_some() {
|
||||
if header.abi != Abi::Rust && attr::find_by_name(attrs, "no_mangle").is_some() {
|
||||
return;
|
||||
}
|
||||
self.check_snake_case(cx, "function", &name.as_str(), Some(span))
|
||||
|
|
|
@ -259,12 +259,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
|
|||
span: Span,
|
||||
_: ast::NodeId) {
|
||||
match fk {
|
||||
FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => {
|
||||
FnKind::ItemFn(_, _, hir::FnHeader { unsafety: hir::Unsafety::Unsafe, .. }, ..) => {
|
||||
self.report_unsafe(cx, span, "declaration of an `unsafe` function")
|
||||
}
|
||||
|
||||
FnKind::Method(_, sig, ..) => {
|
||||
if sig.unsafety == hir::Unsafety::Unsafe {
|
||||
if sig.header.unsafety == hir::Unsafety::Unsafe {
|
||||
self.report_unsafe(cx, span, "implementation of an `unsafe` method")
|
||||
}
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
|
|||
|
||||
fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
|
||||
if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = item.node {
|
||||
if sig.unsafety == hir::Unsafety::Unsafe {
|
||||
if sig.header.unsafety == hir::Unsafety::Unsafe {
|
||||
self.report_unsafe(cx, item.span, "declaration of an `unsafe` method")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -917,7 +917,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
|||
ty::AssociatedKind::Method => {
|
||||
let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
|
||||
FnData {
|
||||
constness: sig.constness,
|
||||
constness: sig.header.constness,
|
||||
arg_names: self.encode_fn_arg_names_for_body(body),
|
||||
sig: self.lazy(&tcx.fn_sig(def_id)),
|
||||
}
|
||||
|
@ -941,7 +941,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
|||
let needs_inline = (generics.requires_monomorphization(self.tcx) ||
|
||||
tcx.codegen_fn_attrs(def_id).requests_inline()) &&
|
||||
!self.metadata_output_only();
|
||||
let is_const_fn = sig.constness == hir::Constness::Const;
|
||||
let is_const_fn = sig.header.constness == hir::Constness::Const;
|
||||
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
|
||||
needs_inline || is_const_fn || always_encode_mir
|
||||
},
|
||||
|
@ -1045,9 +1045,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
|||
self.encode_rendered_const_for_body(body_id)
|
||||
)
|
||||
}
|
||||
hir::ItemFn(_, _, constness, .., body) => {
|
||||
hir::ItemFn(_, header, .., body) => {
|
||||
let data = FnData {
|
||||
constness,
|
||||
constness: header.constness,
|
||||
arg_names: self.encode_fn_arg_names_for_body(body),
|
||||
sig: self.lazy(&tcx.fn_sig(def_id)),
|
||||
};
|
||||
|
@ -1235,7 +1235,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
|||
self.encode_optimized_mir(def_id)
|
||||
}
|
||||
hir::ItemConst(..) => self.encode_optimized_mir(def_id),
|
||||
hir::ItemFn(_, _, constness, ..) => {
|
||||
hir::ItemFn(_, header, ..) => {
|
||||
let generics = tcx.generics_of(def_id);
|
||||
let has_types = generics.params.iter().any(|param| match param.kind {
|
||||
ty::GenericParamDefKind::Type { .. } => true,
|
||||
|
@ -1245,7 +1245,10 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
|||
(has_types || tcx.codegen_fn_attrs(def_id).requests_inline()) &&
|
||||
!self.metadata_output_only();
|
||||
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
|
||||
if needs_inline || constness == hir::Constness::Const || always_encode_mir {
|
||||
if needs_inline
|
||||
|| header.constness == hir::Constness::Const
|
||||
|| always_encode_mir
|
||||
{
|
||||
self.encode_optimized_mir(def_id)
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -380,10 +380,10 @@ fn is_enclosed(tcx: TyCtxt,
|
|||
if used_unsafe.contains(&parent_id) {
|
||||
Some(("block".to_string(), parent_id))
|
||||
} else if let Some(hir::map::NodeItem(&hir::Item {
|
||||
node: hir::ItemFn(_, fn_unsafety, _, _, _, _),
|
||||
node: hir::ItemFn(_, header, _, _),
|
||||
..
|
||||
})) = tcx.hir.find(parent_id) {
|
||||
match fn_unsafety {
|
||||
match header.unsafety {
|
||||
hir::Unsafety::Unsafe => Some(("fn".to_string(), parent_id)),
|
||||
hir::Unsafety::Normal => None,
|
||||
}
|
||||
|
|
|
@ -87,6 +87,13 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
|
||||
if asyncness.is_async() {
|
||||
struct_span_err!(self.session, span, E0706,
|
||||
"trait fns cannot be declared `async`").emit()
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
|
||||
match constness.node {
|
||||
Constness::Const => {
|
||||
|
@ -257,7 +264,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
for impl_item in impl_items {
|
||||
self.invalid_visibility(&impl_item.vis, None);
|
||||
if let ImplItemKind::Method(ref sig, _) = impl_item.node {
|
||||
self.check_trait_fn_not_const(sig.constness);
|
||||
self.check_trait_fn_not_const(sig.header.constness);
|
||||
self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -309,7 +317,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.no_questions_in_bounds(bounds, "supertraits", true);
|
||||
for trait_item in trait_items {
|
||||
if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
|
||||
self.check_trait_fn_not_const(sig.constness);
|
||||
self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness);
|
||||
self.check_trait_fn_not_const(sig.header.constness);
|
||||
if block.is_none() {
|
||||
self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
|
||||
if mut_ident {
|
||||
|
|
|
@ -310,4 +310,5 @@ register_diagnostics! {
|
|||
E0666, // nested `impl Trait` is illegal
|
||||
E0667, // `impl Trait` in projections
|
||||
E0696, // `continue` pointing to a labeled block
|
||||
E0706, // `async fn` in trait
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
|
|||
|
||||
use syntax::visit::{self, FnKind, Visitor};
|
||||
use syntax::attr;
|
||||
use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind};
|
||||
use syntax::ast::{Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind};
|
||||
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
|
||||
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
|
||||
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
|
||||
|
@ -746,15 +746,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
|||
function_kind: FnKind<'tcx>,
|
||||
declaration: &'tcx FnDecl,
|
||||
_: Span,
|
||||
node_id: NodeId) {
|
||||
let rib_kind = match function_kind {
|
||||
FnKind::ItemFn(..) => {
|
||||
ItemRibKind
|
||||
}
|
||||
FnKind::Method(_, _, _, _) => {
|
||||
TraitOrImplItemRibKind
|
||||
}
|
||||
FnKind::Closure(_) => ClosureRibKind(node_id),
|
||||
node_id: NodeId)
|
||||
{
|
||||
let (rib_kind, asyncness) = match function_kind {
|
||||
FnKind::ItemFn(_, ref header, ..) =>
|
||||
(ItemRibKind, header.asyncness),
|
||||
FnKind::Method(_, ref sig, _, _) =>
|
||||
(TraitOrImplItemRibKind, sig.header.asyncness),
|
||||
FnKind::Closure(_) =>
|
||||
// Async closures aren't resolved through `visit_fn`-- they're
|
||||
// processed separately
|
||||
(ClosureRibKind(node_id), IsAsync::NotAsync),
|
||||
};
|
||||
|
||||
// Create a value rib for the function.
|
||||
|
@ -774,7 +776,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
|||
}
|
||||
visit::walk_fn_ret_ty(self, &declaration.output);
|
||||
|
||||
// Resolve the function body.
|
||||
// Resolve the function body, potentially inside the body of an async closure
|
||||
if let IsAsync::Async(async_closure_id) = asyncness {
|
||||
let rib_kind = ClosureRibKind(async_closure_id);
|
||||
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
||||
self.label_ribs.push(Rib::new(rib_kind));
|
||||
}
|
||||
|
||||
match function_kind {
|
||||
FnKind::ItemFn(.., body) |
|
||||
FnKind::Method(.., body) => {
|
||||
|
@ -785,6 +793,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
// Leave the body of the async closure
|
||||
if asyncness.is_async() {
|
||||
self.label_ribs.pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
debug!("(resolving function) leaving function");
|
||||
|
||||
self.label_ribs.pop();
|
||||
|
@ -1475,14 +1489,34 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
|
|||
|resolver, span, error| resolve_error(resolver, span, error))
|
||||
}
|
||||
|
||||
fn resolve_str_path(&mut self, span: Span, crate_root: Option<&str>,
|
||||
components: &[&str], is_value: bool) -> hir::Path {
|
||||
fn resolve_str_path(
|
||||
&mut self,
|
||||
span: Span,
|
||||
crate_root: Option<&str>,
|
||||
components: &[&str],
|
||||
args: Option<P<hir::GenericArgs>>,
|
||||
is_value: bool
|
||||
) -> hir::Path {
|
||||
let mut segments = iter::once(keywords::CrateRoot.name())
|
||||
.chain(
|
||||
crate_root.into_iter()
|
||||
.chain(components.iter().cloned())
|
||||
.map(Symbol::intern)
|
||||
).map(hir::PathSegment::from_name).collect::<Vec<_>>();
|
||||
|
||||
if let Some(args) = args {
|
||||
let name = segments.last().unwrap().name;
|
||||
*segments.last_mut().unwrap() = hir::PathSegment {
|
||||
name,
|
||||
args: Some(args),
|
||||
infer_types: true,
|
||||
};
|
||||
}
|
||||
|
||||
let mut path = hir::Path {
|
||||
span,
|
||||
def: Def::Err,
|
||||
segments: iter::once(keywords::CrateRoot.name()).chain({
|
||||
crate_root.into_iter().chain(components.iter().cloned()).map(Symbol::intern)
|
||||
}).map(hir::PathSegment::from_name).collect(),
|
||||
segments: segments.into(),
|
||||
};
|
||||
|
||||
self.resolve_hir_path(&mut path, is_value);
|
||||
|
@ -2058,7 +2092,7 @@ impl<'a> Resolver<'a> {
|
|||
ItemKind::Ty(_, ref generics) |
|
||||
ItemKind::Struct(_, ref generics) |
|
||||
ItemKind::Union(_, ref generics) |
|
||||
ItemKind::Fn(.., ref generics, _) => {
|
||||
ItemKind::Fn(_, _, ref generics, _) => {
|
||||
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind),
|
||||
|this| visit::walk_item(this, item));
|
||||
}
|
||||
|
@ -2374,7 +2408,7 @@ impl<'a> Resolver<'a> {
|
|||
visit::walk_impl_item(this, impl_item)
|
||||
);
|
||||
}
|
||||
ImplItemKind::Method(_, _) => {
|
||||
ImplItemKind::Method(..) => {
|
||||
// If this is a trait impl, ensure the method
|
||||
// exists in trait
|
||||
this.check_trait_item(impl_item.ident,
|
||||
|
@ -3888,6 +3922,49 @@ impl<'a> Resolver<'a> {
|
|||
visit::walk_expr(self, expr);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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("$");
|
||||
id.push_str(&ex.id.to_string());
|
||||
|
||||
|
|
|
@ -380,17 +380,20 @@ impl Sig for ast::Item {
|
|||
|
||||
Ok(extend_sig(ty, text, defs, vec![]))
|
||||
}
|
||||
ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, _) => {
|
||||
ast::ItemKind::Fn(ref decl, header, ref generics, _) => {
|
||||
let mut text = String::new();
|
||||
if constness.node == ast::Constness::Const {
|
||||
if header.constness.node == ast::Constness::Const {
|
||||
text.push_str("const ");
|
||||
}
|
||||
if unsafety == ast::Unsafety::Unsafe {
|
||||
if header.asyncness.is_async() {
|
||||
text.push_str("async ");
|
||||
}
|
||||
if header.unsafety == ast::Unsafety::Unsafe {
|
||||
text.push_str("unsafe ");
|
||||
}
|
||||
if abi != ::rustc_target::spec::abi::Abi::Rust {
|
||||
if header.abi != ::rustc_target::spec::abi::Abi::Rust {
|
||||
text.push_str("extern");
|
||||
text.push_str(&abi.to_string());
|
||||
text.push_str(&header.abi.to_string());
|
||||
text.push(' ');
|
||||
}
|
||||
text.push_str("fn ");
|
||||
|
@ -914,15 +917,18 @@ fn make_method_signature(
|
|||
) -> Result {
|
||||
// FIXME code dup with function signature
|
||||
let mut text = String::new();
|
||||
if m.constness.node == ast::Constness::Const {
|
||||
if m.header.constness.node == ast::Constness::Const {
|
||||
text.push_str("const ");
|
||||
}
|
||||
if m.unsafety == ast::Unsafety::Unsafe {
|
||||
if m.header.asyncness.is_async() {
|
||||
text.push_str("async ");
|
||||
}
|
||||
if m.header.unsafety == ast::Unsafety::Unsafe {
|
||||
text.push_str("unsafe ");
|
||||
}
|
||||
if m.abi != ::rustc_target::spec::abi::Abi::Rust {
|
||||
if m.header.abi != ::rustc_target::spec::abi::Abi::Rust {
|
||||
text.push_str("extern");
|
||||
text.push_str(&m.abi.to_string());
|
||||
text.push_str(&m.header.abi.to_string());
|
||||
text.push(' ');
|
||||
}
|
||||
text.push_str("fn ");
|
||||
|
|
|
@ -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 Item_::ItemFn(_, _, _, _, ref generics, _) = item.node {
|
||||
if let Item_::ItemFn(_, _, ref generics, _) = item.node {
|
||||
if !generics.params.is_empty() {
|
||||
fcx.tcx.sess.span_err(
|
||||
span,
|
||||
|
|
|
@ -1181,13 +1181,13 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
|
||||
match tcx.hir.get(node_id) {
|
||||
NodeTraitItem(&hir::TraitItem { node: TraitItemKind::Method(ref sig, _), .. }) |
|
||||
NodeImplItem(&hir::ImplItem { node: ImplItemKind::Method(ref sig, _), .. }) => {
|
||||
AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl)
|
||||
NodeTraitItem(hir::TraitItem { node: TraitItemKind::Method(sig, _), .. }) |
|
||||
NodeImplItem(hir::ImplItem { node: ImplItemKind::Method(sig, _), .. }) => {
|
||||
AstConv::ty_of_fn(&icx, sig.header.unsafety, sig.header.abi, &sig.decl)
|
||||
}
|
||||
|
||||
NodeItem(&hir::Item { node: ItemFn(ref decl, unsafety, _, abi, _, _), .. }) => {
|
||||
AstConv::ty_of_fn(&icx, unsafety, abi, decl)
|
||||
NodeItem(hir::Item { node: ItemFn(decl, header, _, _), .. }) => {
|
||||
AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl)
|
||||
}
|
||||
|
||||
NodeForeignItem(&hir::ForeignItem { node: ForeignItemFn(ref fn_decl, _, _), .. }) => {
|
||||
|
|
|
@ -198,9 +198,12 @@ fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function {
|
|||
clean::Function {
|
||||
decl: (did, sig).clean(cx),
|
||||
generics: (cx.tcx.generics_of(did), &predicates).clean(cx),
|
||||
header: hir::FnHeader {
|
||||
unsafety: sig.unsafety(),
|
||||
constness,
|
||||
abi: sig.abi(),
|
||||
constness,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@ pub use self::SelfTy::*;
|
|||
pub use self::FunctionRetTy::*;
|
||||
pub use self::Visibility::{Public, Inherited};
|
||||
|
||||
use syntax;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax;
|
||||
use syntax::ast::{self, AttrStyle, NodeId, Ident};
|
||||
use syntax::attr;
|
||||
use syntax::codemap::{dummy_spanned, Spanned};
|
||||
|
@ -2074,10 +2074,8 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
|
|||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct Method {
|
||||
pub generics: Generics,
|
||||
pub unsafety: hir::Unsafety,
|
||||
pub constness: hir::Constness,
|
||||
pub decl: FnDecl,
|
||||
pub abi: Abi,
|
||||
pub header: hir::FnHeader,
|
||||
}
|
||||
|
||||
impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) {
|
||||
|
@ -2088,28 +2086,23 @@ impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId)
|
|||
Method {
|
||||
decl,
|
||||
generics,
|
||||
unsafety: self.0.unsafety,
|
||||
constness: self.0.constness,
|
||||
abi: self.0.abi
|
||||
header: self.0.header,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct TyMethod {
|
||||
pub unsafety: hir::Unsafety,
|
||||
pub header: hir::FnHeader,
|
||||
pub decl: FnDecl,
|
||||
pub generics: Generics,
|
||||
pub abi: Abi,
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct Function {
|
||||
pub decl: FnDecl,
|
||||
pub generics: Generics,
|
||||
pub unsafety: hir::Unsafety,
|
||||
pub constness: hir::Constness,
|
||||
pub abi: Abi,
|
||||
pub header: hir::FnHeader,
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Function {
|
||||
|
@ -2128,9 +2121,7 @@ impl Clean<Item> for doctree::Function {
|
|||
inner: FunctionItem(Function {
|
||||
decl,
|
||||
generics,
|
||||
unsafety: self.unsafety,
|
||||
constness: self.constness,
|
||||
abi: self.abi,
|
||||
header: self.header,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -2359,10 +2350,9 @@ impl Clean<Item> for hir::TraitItem {
|
|||
(self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
|
||||
});
|
||||
TyMethodItem(TyMethod {
|
||||
unsafety: sig.unsafety.clone(),
|
||||
header: sig.header,
|
||||
decl,
|
||||
generics,
|
||||
abi: sig.abi
|
||||
})
|
||||
}
|
||||
hir::TraitItemKind::Type(ref bounds, ref default) => {
|
||||
|
@ -2461,18 +2451,25 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
|
|||
hir::Constness::NotConst
|
||||
};
|
||||
MethodItem(Method {
|
||||
unsafety: sig.unsafety(),
|
||||
generics,
|
||||
decl,
|
||||
header: hir::FnHeader {
|
||||
unsafety: sig.unsafety(),
|
||||
abi: sig.abi(),
|
||||
constness,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
TyMethodItem(TyMethod {
|
||||
unsafety: sig.unsafety(),
|
||||
generics,
|
||||
decl,
|
||||
header: hir::FnHeader {
|
||||
unsafety: sig.unsafety(),
|
||||
abi: sig.abi(),
|
||||
constness: hir::Constness::NotConst,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -3697,9 +3694,9 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy {
|
|||
});
|
||||
BareFunctionDecl {
|
||||
unsafety: self.unsafety,
|
||||
abi: self.abi,
|
||||
decl,
|
||||
generic_params,
|
||||
abi: self.abi,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3994,7 +3991,7 @@ impl Clean<Vec<Item>> for hir::ForeignMod {
|
|||
let mut items = self.items.clean(cx);
|
||||
for item in &mut items {
|
||||
if let ForeignFunctionItem(ref mut f) = item.inner {
|
||||
f.abi = self.abi;
|
||||
f.header.abi = self.abi;
|
||||
}
|
||||
}
|
||||
items
|
||||
|
@ -4011,9 +4008,12 @@ impl Clean<Item> for hir::ForeignItem {
|
|||
ForeignFunctionItem(Function {
|
||||
decl,
|
||||
generics,
|
||||
header: hir::FnHeader {
|
||||
unsafety: hir::Unsafety::Unsafe,
|
||||
abi: Abi::Rust,
|
||||
constness: hir::Constness::NotConst,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
},
|
||||
})
|
||||
}
|
||||
hir::ForeignItemStatic(ref ty, mutbl) => {
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
pub use self::StructType::*;
|
||||
pub use self::TypeBound::*;
|
||||
|
||||
use rustc_target::spec::abi;
|
||||
use syntax::ast;
|
||||
use syntax::ast::{Name, NodeId};
|
||||
use syntax::attr;
|
||||
|
@ -149,11 +148,9 @@ pub struct Function {
|
|||
pub vis: hir::Visibility,
|
||||
pub stab: Option<attr::Stability>,
|
||||
pub depr: Option<attr::Deprecation>,
|
||||
pub unsafety: hir::Unsafety,
|
||||
pub constness: hir::Constness,
|
||||
pub header: hir::FnHeader,
|
||||
pub whence: Span,
|
||||
pub generics: hir::Generics,
|
||||
pub abi: abi::Abi,
|
||||
pub body: hir::BodyId,
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,10 @@ pub struct UnsafetySpace(pub hir::Unsafety);
|
|||
/// with a space after it.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ConstnessSpace(pub hir::Constness);
|
||||
/// Similarly to VisSpace, this structure is used to render a function asyncness
|
||||
/// with a space after it.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AsyncSpace(pub hir::IsAsync);
|
||||
/// Similar to VisSpace, but used for mutability
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct MutableSpace(pub clean::Mutability);
|
||||
|
@ -962,6 +966,15 @@ impl fmt::Display for ConstnessSpace {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for AsyncSpace {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.0 {
|
||||
hir::IsAsync::Async => write!(f, "async "),
|
||||
hir::IsAsync::NotAsync => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for clean::Import {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
|
|
|
@ -62,13 +62,12 @@ use rustc::middle::stability;
|
|||
use rustc::hir;
|
||||
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::flock;
|
||||
use rustc_target::spec::abi;
|
||||
|
||||
use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability};
|
||||
use doctree;
|
||||
use fold::DocFolder;
|
||||
use html::escape::Escape;
|
||||
use html::format::{ConstnessSpace};
|
||||
use html::format::{AsyncSpace, ConstnessSpace};
|
||||
use html::format::{GenericBounds, WhereClause, href, AbiSpace};
|
||||
use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
|
||||
use html::format::fmt_impl_for_trait_page;
|
||||
|
@ -2405,7 +2404,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
|
|||
|
||||
let unsafety_flag = match myitem.inner {
|
||||
clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func)
|
||||
if func.unsafety == hir::Unsafety::Unsafe => {
|
||||
if func.header.unsafety == hir::Unsafety::Unsafe => {
|
||||
"<a title='unsafe function' href='#'><sup>⚠</sup></a>"
|
||||
}
|
||||
_ => "",
|
||||
|
@ -2575,21 +2574,24 @@ fn item_static(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
|||
|
||||
fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
||||
f: &clean::Function) -> fmt::Result {
|
||||
let name_len = format!("{}{}{}{:#}fn {}{:#}",
|
||||
let name_len = format!("{}{}{}{}{:#}fn {}{:#}",
|
||||
VisSpace(&it.visibility),
|
||||
ConstnessSpace(f.constness),
|
||||
UnsafetySpace(f.unsafety),
|
||||
AbiSpace(f.abi),
|
||||
ConstnessSpace(f.header.constness),
|
||||
UnsafetySpace(f.header.unsafety),
|
||||
AsyncSpace(f.header.asyncness),
|
||||
AbiSpace(f.header.abi),
|
||||
it.name.as_ref().unwrap(),
|
||||
f.generics).len();
|
||||
write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it)?)?;
|
||||
render_attributes(w, it)?;
|
||||
write!(w,
|
||||
"{vis}{constness}{unsafety}{abi}fn {name}{generics}{decl}{where_clause}</pre>",
|
||||
"{vis}{constness}{unsafety}{asyncness}{abi}fn \
|
||||
{name}{generics}{decl}{where_clause}</pre>",
|
||||
vis = VisSpace(&it.visibility),
|
||||
constness = ConstnessSpace(f.constness),
|
||||
unsafety = UnsafetySpace(f.unsafety),
|
||||
abi = AbiSpace(f.abi),
|
||||
constness = ConstnessSpace(f.header.constness),
|
||||
unsafety = UnsafetySpace(f.header.unsafety),
|
||||
asyncness = AsyncSpace(f.header.asyncness),
|
||||
abi = AbiSpace(f.header.abi),
|
||||
name = it.name.as_ref().unwrap(),
|
||||
generics = f.generics,
|
||||
where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
|
||||
|
@ -2999,9 +3001,7 @@ fn render_assoc_item(w: &mut fmt::Formatter,
|
|||
parent: ItemType) -> fmt::Result {
|
||||
fn method(w: &mut fmt::Formatter,
|
||||
meth: &clean::Item,
|
||||
unsafety: hir::Unsafety,
|
||||
constness: hir::Constness,
|
||||
abi: abi::Abi,
|
||||
header: hir::FnHeader,
|
||||
g: &clean::Generics,
|
||||
d: &clean::FnDecl,
|
||||
link: AssocItemLink,
|
||||
|
@ -3024,11 +3024,12 @@ fn render_assoc_item(w: &mut fmt::Formatter,
|
|||
href(did).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
|
||||
}
|
||||
};
|
||||
let mut head_len = format!("{}{}{}{:#}fn {}{:#}",
|
||||
let mut head_len = format!("{}{}{}{}{:#}fn {}{:#}",
|
||||
VisSpace(&meth.visibility),
|
||||
ConstnessSpace(constness),
|
||||
UnsafetySpace(unsafety),
|
||||
AbiSpace(abi),
|
||||
ConstnessSpace(header.constness),
|
||||
UnsafetySpace(header.unsafety),
|
||||
AsyncSpace(header.asyncness),
|
||||
AbiSpace(header.abi),
|
||||
name,
|
||||
*g).len();
|
||||
let (indent, end_newline) = if parent == ItemType::Trait {
|
||||
|
@ -3038,12 +3039,13 @@ fn render_assoc_item(w: &mut fmt::Formatter,
|
|||
(0, true)
|
||||
};
|
||||
render_attributes(w, meth)?;
|
||||
write!(w, "{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
|
||||
write!(w, "{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
|
||||
{generics}{decl}{where_clause}",
|
||||
VisSpace(&meth.visibility),
|
||||
ConstnessSpace(constness),
|
||||
UnsafetySpace(unsafety),
|
||||
AbiSpace(abi),
|
||||
ConstnessSpace(header.constness),
|
||||
UnsafetySpace(header.unsafety),
|
||||
AsyncSpace(header.asyncness),
|
||||
AbiSpace(header.abi),
|
||||
href = href,
|
||||
name = name,
|
||||
generics = *g,
|
||||
|
@ -3061,12 +3063,10 @@ fn render_assoc_item(w: &mut fmt::Formatter,
|
|||
match item.inner {
|
||||
clean::StrippedItem(..) => Ok(()),
|
||||
clean::TyMethodItem(ref m) => {
|
||||
method(w, item, m.unsafety, hir::Constness::NotConst,
|
||||
m.abi, &m.generics, &m.decl, link, parent)
|
||||
method(w, item, m.header, &m.generics, &m.decl, link, parent)
|
||||
}
|
||||
clean::MethodItem(ref m) => {
|
||||
method(w, item, m.unsafety, m.constness,
|
||||
m.abi, &m.generics, &m.decl, link, parent)
|
||||
method(w, item, m.header, &m.generics, &m.decl, link, parent)
|
||||
}
|
||||
clean::AssociatedConstItem(ref ty, ref default) => {
|
||||
assoc_const(w, item, ty, default.as_ref(), link)
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
use std::mem;
|
||||
|
||||
use rustc_target::spec::abi;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax_pos::Span;
|
||||
|
@ -172,9 +171,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
|
|||
|
||||
pub fn visit_fn(&mut self, item: &hir::Item,
|
||||
name: ast::Name, fd: &hir::FnDecl,
|
||||
unsafety: &hir::Unsafety,
|
||||
constness: hir::Constness,
|
||||
abi: &abi::Abi,
|
||||
header: hir::FnHeader,
|
||||
gen: &hir::Generics,
|
||||
body: hir::BodyId) -> Function {
|
||||
debug!("Visiting fn");
|
||||
|
@ -188,9 +185,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
|
|||
name,
|
||||
whence: item.span,
|
||||
generics: gen.clone(),
|
||||
unsafety: *unsafety,
|
||||
constness,
|
||||
abi: *abi,
|
||||
header,
|
||||
body,
|
||||
}
|
||||
}
|
||||
|
@ -463,9 +458,8 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
|
|||
om.structs.push(self.visit_variant_data(item, name, sd, gen)),
|
||||
hir::ItemUnion(ref sd, ref gen) =>
|
||||
om.unions.push(self.visit_union_data(item, name, sd, gen)),
|
||||
hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, body) =>
|
||||
om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
|
||||
constness, abi, gen, body)),
|
||||
hir::ItemFn(ref fd, header, ref gen, body) =>
|
||||
om.fns.push(self.visit_fn(item, name, &**fd, header, gen, body)),
|
||||
hir::ItemTy(ref ty, ref gen) => {
|
||||
let t = Typedef {
|
||||
ty: ty.clone(),
|
||||
|
|
116
src/libstd/future.rs
Normal file
116
src/libstd/future.rs
Normal file
|
@ -0,0 +1,116 @@
|
|||
// 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.
|
||||
|
||||
//! Asynchronous values.
|
||||
|
||||
use core::cell::Cell;
|
||||
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};
|
||||
|
||||
#[doc(inline)]
|
||||
pub use core::future::*;
|
||||
|
||||
/// 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 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> {
|
||||
set_task_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")]
|
||||
/// Sets the thread-local task context used by async/await futures.
|
||||
pub fn set_task_cx<F, R>(cx: &mut task::Context, f: F) -> R
|
||||
where
|
||||
F: FnOnce() -> R
|
||||
{
|
||||
let old_cx = TLS_CX.with(|tls_cx| {
|
||||
tls_cx.replace(NonNull::new(
|
||||
cx
|
||||
as *mut task::Context
|
||||
as *mut ()
|
||||
as *mut task::Context<'static>
|
||||
))
|
||||
});
|
||||
let _reset_cx = SetOnDrop(old_cx);
|
||||
f()
|
||||
}
|
||||
|
||||
#[unstable(feature = "gen_future", issue = "50547")]
|
||||
/// Retrieves the thread-local task context used by async/await futures.
|
||||
///
|
||||
/// This function acquires exclusive access to the task context.
|
||||
///
|
||||
/// Panics if no task has been set or if the task context has already been
|
||||
/// retrived by a surrounding call to get_task_cx.
|
||||
pub fn get_task_cx<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut task::Context) -> R
|
||||
{
|
||||
let cx_ptr = TLS_CX.with(|tls_cx| {
|
||||
// Clear the entry so that nested `with_get_cx` calls
|
||||
// will fail or set their own value.
|
||||
tls_cx.replace(None)
|
||||
});
|
||||
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()) }
|
||||
}
|
||||
|
||||
#[unstable(feature = "gen_future", issue = "50547")]
|
||||
/// Polls a future in the current thread-local task context.
|
||||
pub fn poll_in_task_cx<F>(f: &mut PinMut<F>) -> Poll<F::Output>
|
||||
where
|
||||
F: Future
|
||||
{
|
||||
get_task_cx(|cx| f.reborrow().poll(cx))
|
||||
}
|
|
@ -263,6 +263,7 @@
|
|||
#![feature(fn_traits)]
|
||||
#![feature(fnbox)]
|
||||
#![feature(futures_api)]
|
||||
#![feature(generator_trait)]
|
||||
#![feature(hashmap_internals)]
|
||||
#![feature(int_error_internals)]
|
||||
#![feature(integer_atomics)]
|
||||
|
@ -462,22 +463,6 @@ pub use core::u128;
|
|||
#[stable(feature = "core_hint", since = "1.27.0")]
|
||||
pub use core::hint;
|
||||
|
||||
#[unstable(feature = "futures_api",
|
||||
reason = "futures in libcore are unstable",
|
||||
issue = "50547")]
|
||||
pub mod task {
|
||||
//! Types and Traits for working with asynchronous tasks.
|
||||
#[doc(inline)]
|
||||
pub use core::task::*;
|
||||
#[doc(inline)]
|
||||
pub use alloc_crate::task::*;
|
||||
}
|
||||
|
||||
#[unstable(feature = "futures_api",
|
||||
reason = "futures in libcore are unstable",
|
||||
issue = "50547")]
|
||||
pub use core::future;
|
||||
|
||||
pub mod f32;
|
||||
pub mod f64;
|
||||
|
||||
|
@ -499,6 +484,22 @@ pub mod process;
|
|||
pub mod sync;
|
||||
pub mod time;
|
||||
|
||||
#[unstable(feature = "futures_api",
|
||||
reason = "futures in libcore are unstable",
|
||||
issue = "50547")]
|
||||
pub mod task {
|
||||
//! Types and Traits for working with asynchronous tasks.
|
||||
#[doc(inline)]
|
||||
pub use core::task::*;
|
||||
#[doc(inline)]
|
||||
pub use alloc_crate::task::*;
|
||||
}
|
||||
|
||||
#[unstable(feature = "futures_api",
|
||||
reason = "futures in libcore are unstable",
|
||||
issue = "50547")]
|
||||
pub mod future;
|
||||
|
||||
// Platform-abstraction modules
|
||||
#[macro_use]
|
||||
mod sys_common;
|
||||
|
|
|
@ -213,6 +213,25 @@ macro_rules! eprintln {
|
|||
($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[unstable(feature = "await_macro", issue = "50547")]
|
||||
#[allow_internal_unstable]
|
||||
#[allow_internal_unsafe]
|
||||
macro_rules! await {
|
||||
($e:expr) => { {
|
||||
let mut pinned = $e;
|
||||
let mut pinned = unsafe { $crate::mem::PinMut::new_unchecked(&mut pinned) };
|
||||
loop {
|
||||
match $crate::future::poll_in_task_cx(&mut pinned) {
|
||||
// FIXME(cramertj) prior to stabilizing await, we have to ensure that this
|
||||
// can't be used to create a generator on stable via `|| await!()`.
|
||||
$crate::task::Poll::Pending => yield,
|
||||
$crate::task::Poll::Ready(x) => break x,
|
||||
}
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
|
|
@ -17,7 +17,7 @@ pub use util::ThinVec;
|
|||
pub use util::parser::ExprPrecedence;
|
||||
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use codemap::{respan, Spanned};
|
||||
use codemap::{dummy_spanned, respan, Spanned};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use ext::hygiene::{Mark, SyntaxContext};
|
||||
use print::pprust;
|
||||
|
@ -987,6 +987,7 @@ impl Expr {
|
|||
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
||||
ExprKind::Block(..) => ExprPrecedence::Block,
|
||||
ExprKind::Catch(..) => ExprPrecedence::Catch,
|
||||
ExprKind::Async(..) => ExprPrecedence::Async,
|
||||
ExprKind::Assign(..) => ExprPrecedence::Assign,
|
||||
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
|
||||
ExprKind::Field(..) => ExprPrecedence::Field,
|
||||
|
@ -1094,9 +1095,18 @@ pub enum ExprKind {
|
|||
/// A closure (for example, `move |a, b, c| a + b + c`)
|
||||
///
|
||||
/// 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: { ... }`)
|
||||
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 { ... }`)
|
||||
Catch(P<Block>),
|
||||
|
||||
|
@ -1325,9 +1335,7 @@ pub struct MutTy {
|
|||
/// or in an implementation.
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub struct MethodSig {
|
||||
pub unsafety: Unsafety,
|
||||
pub constness: Spanned<Constness>,
|
||||
pub abi: Abi,
|
||||
pub header: FnHeader,
|
||||
pub decl: P<FnDecl>,
|
||||
}
|
||||
|
||||
|
@ -1708,6 +1716,22 @@ pub enum Unsafety {
|
|||
Normal,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum IsAsync {
|
||||
Async(NodeId),
|
||||
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)]
|
||||
pub enum Constness {
|
||||
Const,
|
||||
|
@ -2009,6 +2033,29 @@ pub struct Item {
|
|||
pub tokens: Option<TokenStream>,
|
||||
}
|
||||
|
||||
/// A function header
|
||||
///
|
||||
/// All the information between the visibility & the name of the function is
|
||||
/// included in this struct (e.g. `async unsafe fn` or `const extern "C" fn`)
|
||||
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub struct FnHeader {
|
||||
pub unsafety: Unsafety,
|
||||
pub asyncness: IsAsync,
|
||||
pub constness: Spanned<Constness>,
|
||||
pub abi: Abi,
|
||||
}
|
||||
|
||||
impl Default for FnHeader {
|
||||
fn default() -> FnHeader {
|
||||
FnHeader {
|
||||
unsafety: Unsafety::Normal,
|
||||
asyncness: IsAsync::NotAsync,
|
||||
constness: dummy_spanned(Constness::NotConst),
|
||||
abi: Abi::Rust,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum ItemKind {
|
||||
/// An `extern crate` item, with optional *original* crate name if the crate was renamed.
|
||||
|
@ -2030,7 +2077,7 @@ pub enum ItemKind {
|
|||
/// A function declaration (`fn` or `pub fn`).
|
||||
///
|
||||
/// E.g. `fn foo(bar: usize) -> usize { .. }`
|
||||
Fn(P<FnDecl>, Unsafety, Spanned<Constness>, Abi, Generics, P<Block>),
|
||||
Fn(P<FnDecl>, FnHeader, Generics, P<Block>),
|
||||
/// A module declaration (`mod` or `pub mod`).
|
||||
///
|
||||
/// E.g. `mod foo;` or `mod foo { .. }`
|
||||
|
|
|
@ -915,6 +915,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
fn_decl_span: Span) // span of the `|...|` part
|
||||
-> P<ast::Expr> {
|
||||
self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref,
|
||||
ast::IsAsync::NotAsync,
|
||||
ast::Movability::Movable,
|
||||
fn_decl,
|
||||
body,
|
||||
|
@ -935,6 +936,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
// the entire lambda body. Probably we should extend the API
|
||||
// here, but that's not entirely clear.
|
||||
self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref,
|
||||
ast::IsAsync::NotAsync,
|
||||
ast::Movability::Movable,
|
||||
fn_decl,
|
||||
body,
|
||||
|
@ -1008,9 +1010,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
name,
|
||||
Vec::new(),
|
||||
ast::ItemKind::Fn(self.fn_decl(inputs, ast::FunctionRetTy::Ty(output)),
|
||||
ast::Unsafety::Normal,
|
||||
dummy_spanned(ast::Constness::NotConst),
|
||||
Abi::Rust,
|
||||
ast::FnHeader {
|
||||
unsafety: ast::Unsafety::Normal,
|
||||
asyncness: ast::IsAsync::NotAsync,
|
||||
constness: dummy_spanned(ast::Constness::NotConst),
|
||||
abi: Abi::Rust,
|
||||
},
|
||||
generics,
|
||||
body))
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ use rustc_target::spec::abi::Abi;
|
|||
use ast::{self, NodeId, PatKind, RangeEnd};
|
||||
use attr;
|
||||
use edition::{ALL_EDITIONS, Edition};
|
||||
use codemap::Spanned;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use errors::{DiagnosticBuilder, Handler, FatalError};
|
||||
use visit::{self, FnKind, Visitor};
|
||||
|
@ -309,7 +308,7 @@ declare_features! (
|
|||
// Declarative macros 2.0 (`macro`).
|
||||
(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),
|
||||
|
||||
// `extern "msp430-interrupt" fn()`
|
||||
|
@ -468,12 +467,14 @@ declare_features! (
|
|||
// 'a: { break 'a; }
|
||||
(active, label_break_value, "1.28.0", Some(48594), None),
|
||||
|
||||
|
||||
// #[panic_implementation]
|
||||
(active, panic_implementation, "1.28.0", Some(44489), None),
|
||||
|
||||
// #[doc(keyword = "...")]
|
||||
(active, doc_keyword, "1.28.0", Some(51315), None),
|
||||
|
||||
// Allows async and await syntax
|
||||
(active, async_await, "1.28.0", Some(50547), None),
|
||||
);
|
||||
|
||||
declare_features! (
|
||||
|
@ -1721,6 +1722,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
"labels on blocks are unstable");
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Closure(_, ast::IsAsync::Async(_), ..) => {
|
||||
gate_feature_post!(&self, async_await, e.span, "async closures are unstable");
|
||||
}
|
||||
ast::ExprKind::Async(..) => {
|
||||
gate_feature_post!(&self, async_await, e.span, "async blocks are unstable");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_expr(self, e);
|
||||
|
@ -1760,9 +1767,13 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
fn_decl: &'a ast::FnDecl,
|
||||
span: Span,
|
||||
_node_id: NodeId) {
|
||||
// check for const fn declarations
|
||||
if let FnKind::ItemFn(_, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) =
|
||||
fn_kind {
|
||||
match fn_kind {
|
||||
FnKind::ItemFn(_, header, _, _) => {
|
||||
// check for const fn and async fn declarations
|
||||
if header.asyncness.is_async() {
|
||||
gate_feature_post!(&self, async_await, span, "async fn is unstable");
|
||||
}
|
||||
if header.constness.node == ast::Constness::Const {
|
||||
gate_feature_post!(&self, const_fn, span, "const fn is unstable");
|
||||
}
|
||||
// stability of const fn methods are covered in
|
||||
|
@ -1770,10 +1781,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
// because default methods don't pass through this
|
||||
// point.
|
||||
|
||||
match fn_kind {
|
||||
FnKind::ItemFn(_, _, _, abi, _, _) |
|
||||
FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
|
||||
self.check_abi(abi, span);
|
||||
self.check_abi(header.abi, span);
|
||||
}
|
||||
FnKind::Method(_, sig, _, _) => {
|
||||
self.check_abi(sig.header.abi, span);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -1784,9 +1795,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
match ti.node {
|
||||
ast::TraitItemKind::Method(ref sig, ref block) => {
|
||||
if block.is_none() {
|
||||
self.check_abi(sig.abi, ti.span);
|
||||
self.check_abi(sig.header.abi, ti.span);
|
||||
}
|
||||
if sig.constness.node == ast::Constness::Const {
|
||||
if sig.header.constness.node == ast::Constness::Const {
|
||||
gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
|
||||
}
|
||||
}
|
||||
|
@ -1820,7 +1831,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
|
||||
match ii.node {
|
||||
ast::ImplItemKind::Method(ref sig, _) => {
|
||||
if sig.constness.node == ast::Constness::Const {
|
||||
if sig.header.constness.node == ast::Constness::Const {
|
||||
gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,10 @@ pub trait Folder : Sized {
|
|||
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 {
|
||||
noop_fold_struct_field(sf, self)
|
||||
}
|
||||
|
@ -881,11 +885,12 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
|
|||
ItemKind::Const(t, e) => {
|
||||
ItemKind::Const(folder.fold_ty(t), folder.fold_expr(e))
|
||||
}
|
||||
ItemKind::Fn(decl, unsafety, constness, abi, generics, body) => {
|
||||
ItemKind::Fn(decl, header, generics, body) => {
|
||||
let generics = folder.fold_generics(generics);
|
||||
let header = folder.fold_fn_header(header);
|
||||
let decl = folder.fold_fn_decl(decl);
|
||||
let body = folder.fold_block(body);
|
||||
ItemKind::Fn(decl, unsafety, constness, abi, generics, body)
|
||||
ItemKind::Fn(decl, header, generics, body)
|
||||
}
|
||||
ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)),
|
||||
ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)),
|
||||
|
@ -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 {
|
||||
Mod {
|
||||
inner: folder.new_span(inner),
|
||||
|
@ -1082,9 +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 {
|
||||
MethodSig {
|
||||
abi: sig.abi,
|
||||
unsafety: sig.unsafety,
|
||||
constness: sig.constness,
|
||||
header: folder.fold_fn_header(sig.header),
|
||||
decl: folder.fold_fn_decl(sig.decl)
|
||||
}
|
||||
}
|
||||
|
@ -1237,8 +1248,13 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
|
|||
ExprKind::Match(folder.fold_expr(expr),
|
||||
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,
|
||||
asyncness,
|
||||
movability,
|
||||
folder.fold_fn_decl(decl),
|
||||
folder.fold_expr(body),
|
||||
|
@ -1248,6 +1264,9 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
|
|||
ExprKind::Block(folder.fold_block(blk),
|
||||
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(folder.fold_expr(el), folder.fold_expr(er))
|
||||
}
|
||||
|
|
|
@ -928,12 +928,15 @@ mod tests {
|
|||
output: ast::FunctionRetTy::Default(sp(15, 15)),
|
||||
variadic: false
|
||||
}),
|
||||
ast::Unsafety::Normal,
|
||||
Spanned {
|
||||
ast::FnHeader {
|
||||
unsafety: ast::Unsafety::Normal,
|
||||
asyncness: ast::IsAsync::NotAsync,
|
||||
constness: Spanned {
|
||||
span: sp(0,2),
|
||||
node: ast::Constness::NotConst,
|
||||
},
|
||||
Abi::Rust,
|
||||
abi: Abi::Rust,
|
||||
},
|
||||
ast::Generics{
|
||||
params: Vec::new(),
|
||||
where_clause: ast::WhereClause {
|
||||
|
|
|
@ -19,11 +19,11 @@ use ast::{Constness, Crate};
|
|||
use ast::Defaultness;
|
||||
use ast::EnumDef;
|
||||
use ast::{Expr, ExprKind, RangeLimits};
|
||||
use ast::{Field, FnDecl};
|
||||
use ast::{Field, FnDecl, FnHeader};
|
||||
use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
|
||||
use ast::{GenericParam, GenericParamKind};
|
||||
use ast::GenericArg;
|
||||
use ast::{Ident, ImplItem, IsAuto, Item, ItemKind};
|
||||
use ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind};
|
||||
use ast::{Label, Lifetime, Lit, LitKind};
|
||||
use ast::Local;
|
||||
use ast::MacStmtStyle;
|
||||
|
@ -43,7 +43,7 @@ use ast::{BinOpKind, UnOp};
|
|||
use ast::{RangeEnd, RangeSyntax};
|
||||
use {ast, attr};
|
||||
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 parse::{self, SeqSep, classify, token};
|
||||
use parse::lexer::TokenAndSpan;
|
||||
|
@ -1296,6 +1296,15 @@ impl<'a> Parser<'a> {
|
|||
})))
|
||||
}
|
||||
|
||||
/// Parse asyncness: `async` or nothing
|
||||
fn parse_asyncness(&mut self) -> IsAsync {
|
||||
if self.eat_keyword(keywords::Async) {
|
||||
IsAsync::Async(ast::DUMMY_NODE_ID)
|
||||
} else {
|
||||
IsAsync::NotAsync
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse unsafety: `unsafe` or nothing.
|
||||
fn parse_unsafety(&mut self) -> Unsafety {
|
||||
if self.eat_keyword(keywords::Unsafe) {
|
||||
|
@ -1345,7 +1354,7 @@ impl<'a> Parser<'a> {
|
|||
// trait item macro.
|
||||
(keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default())
|
||||
} else {
|
||||
let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
|
||||
let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
|
||||
|
||||
let ident = self.parse_ident()?;
|
||||
let mut generics = self.parse_generics()?;
|
||||
|
@ -1359,10 +1368,13 @@ impl<'a> Parser<'a> {
|
|||
generics.where_clause = self.parse_where_clause()?;
|
||||
|
||||
let sig = ast::MethodSig {
|
||||
header: FnHeader {
|
||||
unsafety,
|
||||
constness,
|
||||
decl: d,
|
||||
abi,
|
||||
asyncness,
|
||||
},
|
||||
decl: d,
|
||||
};
|
||||
|
||||
let body = match self.token {
|
||||
|
@ -2258,6 +2270,15 @@ impl<'a> Parser<'a> {
|
|||
hi = path.span;
|
||||
return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs));
|
||||
}
|
||||
if self.span.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) {
|
||||
return self.parse_lambda_expr(attrs);
|
||||
}
|
||||
|
@ -3258,6 +3279,13 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
Movability::Movable
|
||||
};
|
||||
let asyncness = if self.span.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) {
|
||||
CaptureBy::Value
|
||||
} else {
|
||||
|
@ -3280,7 +3308,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
Ok(self.mk_expr(
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -3358,6 +3386,24 @@ impl<'a> Parser<'a> {
|
|||
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)
|
||||
fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
|
||||
-> PResult<'a, P<Expr>>
|
||||
|
@ -4292,6 +4338,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 {
|
||||
self.token.is_keyword(keywords::Do) &&
|
||||
self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) &&
|
||||
|
@ -5358,6 +5416,7 @@ impl<'a> Parser<'a> {
|
|||
/// Parse an item-position function declaration.
|
||||
fn parse_item_fn(&mut self,
|
||||
unsafety: Unsafety,
|
||||
asyncness: IsAsync,
|
||||
constness: Spanned<Constness>,
|
||||
abi: Abi)
|
||||
-> PResult<'a, ItemInfo> {
|
||||
|
@ -5365,7 +5424,8 @@ impl<'a> Parser<'a> {
|
|||
let decl = self.parse_fn_decl(false)?;
|
||||
generics.where_clause = self.parse_where_clause()?;
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
Ok((ident, ItemKind::Fn(decl, unsafety, constness, abi, generics, body), Some(inner_attrs)))
|
||||
let header = FnHeader { unsafety, asyncness, constness, abi };
|
||||
Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs)))
|
||||
}
|
||||
|
||||
/// true if we are looking at `const ID`, false for things like `const fn` etc
|
||||
|
@ -5383,10 +5443,18 @@ impl<'a> Parser<'a> {
|
|||
/// - `const unsafe fn`
|
||||
/// - `extern fn`
|
||||
/// - etc
|
||||
fn parse_fn_front_matter(&mut self) -> PResult<'a, (Spanned<Constness>, Unsafety, Abi)> {
|
||||
fn parse_fn_front_matter(&mut self)
|
||||
-> PResult<'a, (
|
||||
Spanned<Constness>,
|
||||
Unsafety,
|
||||
IsAsync,
|
||||
Abi
|
||||
)>
|
||||
{
|
||||
let is_const_fn = self.eat_keyword(keywords::Const);
|
||||
let const_span = self.prev_span;
|
||||
let unsafety = self.parse_unsafety();
|
||||
let asyncness = self.parse_asyncness();
|
||||
let (constness, unsafety, abi) = if is_const_fn {
|
||||
(respan(const_span, Constness::Const), unsafety, Abi::Rust)
|
||||
} else {
|
||||
|
@ -5398,7 +5466,7 @@ impl<'a> Parser<'a> {
|
|||
(respan(self.prev_span, Constness::NotConst), unsafety, abi)
|
||||
};
|
||||
self.expect_keyword(keywords::Fn)?;
|
||||
Ok((constness, unsafety, abi))
|
||||
Ok((constness, unsafety, asyncness, abi))
|
||||
}
|
||||
|
||||
/// Parse an impl item.
|
||||
|
@ -5533,19 +5601,18 @@ impl<'a> Parser<'a> {
|
|||
Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
|
||||
ast::ImplItemKind::Macro(mac)))
|
||||
} else {
|
||||
let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
|
||||
let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
|
||||
let ident = self.parse_ident()?;
|
||||
let mut generics = self.parse_generics()?;
|
||||
let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?;
|
||||
generics.where_clause = self.parse_where_clause()?;
|
||||
*at_end = true;
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(ast::MethodSig {
|
||||
abi,
|
||||
unsafety,
|
||||
constness,
|
||||
decl,
|
||||
}, body)))
|
||||
let header = ast::FnHeader { abi, unsafety, constness, asyncness };
|
||||
Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(
|
||||
ast::MethodSig { header, decl },
|
||||
body
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6631,6 +6698,7 @@ impl<'a> Parser<'a> {
|
|||
let abi = opt_abi.unwrap_or(Abi::C);
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(Unsafety::Normal,
|
||||
IsAsync::NotAsync,
|
||||
respan(fn_span, Constness::NotConst),
|
||||
abi)?;
|
||||
let prev_span = self.prev_span;
|
||||
|
@ -6674,6 +6742,7 @@ impl<'a> Parser<'a> {
|
|||
self.bump();
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(unsafety,
|
||||
IsAsync::NotAsync,
|
||||
respan(const_span, Constness::Const),
|
||||
Abi::Rust)?;
|
||||
let prev_span = self.prev_span;
|
||||
|
@ -6701,6 +6770,34 @@ impl<'a> Parser<'a> {
|
|||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
}
|
||||
|
||||
// `unsafe async fn` or `async fn`
|
||||
if (
|
||||
self.check_keyword(keywords::Unsafe) &&
|
||||
self.look_ahead(1, |t| t.is_keyword(keywords::Async))
|
||||
) || (
|
||||
self.check_keyword(keywords::Async) &&
|
||||
self.look_ahead(1, |t| t.is_keyword(keywords::Fn))
|
||||
)
|
||||
{
|
||||
// ASYNC FUNCTION ITEM
|
||||
let unsafety = self.parse_unsafety();
|
||||
self.expect_keyword(keywords::Async)?;
|
||||
self.expect_keyword(keywords::Fn)?;
|
||||
let fn_span = self.prev_span;
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(unsafety,
|
||||
IsAsync::Async(ast::DUMMY_NODE_ID),
|
||||
respan(fn_span, Constness::NotConst),
|
||||
Abi::Rust)?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
}
|
||||
if self.check_keyword(keywords::Unsafe) &&
|
||||
(self.look_ahead(1, |t| t.is_keyword(keywords::Trait)) ||
|
||||
self.look_ahead(1, |t| t.is_keyword(keywords::Auto)))
|
||||
|
@ -6746,6 +6843,7 @@ impl<'a> Parser<'a> {
|
|||
let fn_span = self.prev_span;
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(Unsafety::Normal,
|
||||
IsAsync::NotAsync,
|
||||
respan(fn_span, Constness::NotConst),
|
||||
Abi::Rust)?;
|
||||
let prev_span = self.prev_span;
|
||||
|
@ -6771,6 +6869,7 @@ impl<'a> Parser<'a> {
|
|||
let fn_span = self.prev_span;
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(Unsafety::Unsafe,
|
||||
IsAsync::NotAsync,
|
||||
respan(fn_span, Constness::NotConst),
|
||||
abi)?;
|
||||
let prev_span = self.prev_span;
|
||||
|
|
|
@ -373,14 +373,13 @@ pub fn vis_to_string(v: &ast::Visibility) -> String {
|
|||
}
|
||||
|
||||
pub fn fun_to_string(decl: &ast::FnDecl,
|
||||
unsafety: ast::Unsafety,
|
||||
constness: ast::Constness,
|
||||
header: ast::FnHeader,
|
||||
name: ast::Ident,
|
||||
generics: &ast::Generics)
|
||||
-> String {
|
||||
to_string(|s| {
|
||||
s.head("")?;
|
||||
s.print_fn(decl, unsafety, constness, Abi::Rust, Some(name),
|
||||
s.print_fn(decl, header, Some(name),
|
||||
generics, &codemap::dummy_spanned(ast::VisibilityKind::Inherited))?;
|
||||
s.end()?; // Close the head box
|
||||
s.end() // Close the outer box
|
||||
|
@ -1118,9 +1117,8 @@ impl<'a> State<'a> {
|
|||
match item.node {
|
||||
ast::ForeignItemKind::Fn(ref decl, ref generics) => {
|
||||
self.head("")?;
|
||||
self.print_fn(decl, ast::Unsafety::Normal,
|
||||
ast::Constness::NotConst,
|
||||
Abi::Rust, Some(item.ident),
|
||||
self.print_fn(decl, ast::FnHeader::default(),
|
||||
Some(item.ident),
|
||||
generics, &item.vis)?;
|
||||
self.end()?; // end head-ibox
|
||||
self.s.word(";")?;
|
||||
|
@ -1249,13 +1247,11 @@ impl<'a> State<'a> {
|
|||
self.s.word(";")?;
|
||||
self.end()?; // end the outer cbox
|
||||
}
|
||||
ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
|
||||
ast::ItemKind::Fn(ref decl, header, ref typarams, ref body) => {
|
||||
self.head("")?;
|
||||
self.print_fn(
|
||||
decl,
|
||||
unsafety,
|
||||
constness.node,
|
||||
abi,
|
||||
header,
|
||||
Some(item.ident),
|
||||
typarams,
|
||||
&item.vis
|
||||
|
@ -1582,9 +1578,7 @@ impl<'a> State<'a> {
|
|||
vis: &ast::Visibility)
|
||||
-> io::Result<()> {
|
||||
self.print_fn(&m.decl,
|
||||
m.unsafety,
|
||||
m.constness.node,
|
||||
m.abi,
|
||||
m.header,
|
||||
Some(ident),
|
||||
&generics,
|
||||
vis)
|
||||
|
@ -2177,8 +2171,10 @@ impl<'a> State<'a> {
|
|||
}
|
||||
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_asyncness(asyncness)?;
|
||||
self.print_capture_clause(capture_clause)?;
|
||||
|
||||
self.print_fn_block_args(decl)?;
|
||||
|
@ -2202,6 +2198,12 @@ impl<'a> State<'a> {
|
|||
self.ibox(0)?;
|
||||
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) => {
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_maybe_paren(lhs, prec + 1)?;
|
||||
|
@ -2740,13 +2742,11 @@ impl<'a> State<'a> {
|
|||
|
||||
pub fn print_fn(&mut self,
|
||||
decl: &ast::FnDecl,
|
||||
unsafety: ast::Unsafety,
|
||||
constness: ast::Constness,
|
||||
abi: abi::Abi,
|
||||
header: ast::FnHeader,
|
||||
name: Option<ast::Ident>,
|
||||
generics: &ast::Generics,
|
||||
vis: &ast::Visibility) -> io::Result<()> {
|
||||
self.print_fn_header_info(unsafety, constness, abi, vis)?;
|
||||
self.print_fn_header_info(header, vis)?;
|
||||
|
||||
if let Some(name) = name {
|
||||
self.nbsp()?;
|
||||
|
@ -2800,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)
|
||||
-> io::Result<()> {
|
||||
match capture_clause {
|
||||
|
@ -3058,9 +3066,7 @@ impl<'a> State<'a> {
|
|||
span: syntax_pos::DUMMY_SP,
|
||||
};
|
||||
self.print_fn(decl,
|
||||
unsafety,
|
||||
ast::Constness::NotConst,
|
||||
abi,
|
||||
ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() },
|
||||
name,
|
||||
&generics,
|
||||
&codemap::dummy_spanned(ast::VisibilityKind::Inherited))?;
|
||||
|
@ -3123,22 +3129,21 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
pub fn print_fn_header_info(&mut self,
|
||||
unsafety: ast::Unsafety,
|
||||
constness: ast::Constness,
|
||||
abi: Abi,
|
||||
header: ast::FnHeader,
|
||||
vis: &ast::Visibility) -> io::Result<()> {
|
||||
self.s.word(&visibility_qualified(vis, ""))?;
|
||||
|
||||
match constness {
|
||||
match header.constness.node {
|
||||
ast::Constness::NotConst => {}
|
||||
ast::Constness::Const => self.word_nbsp("const")?
|
||||
}
|
||||
|
||||
self.print_unsafety(unsafety)?;
|
||||
self.print_asyncness(header.asyncness)?;
|
||||
self.print_unsafety(header.unsafety)?;
|
||||
|
||||
if abi != Abi::Rust {
|
||||
if header.abi != Abi::Rust {
|
||||
self.word_nbsp("extern")?;
|
||||
self.word_nbsp(&abi.to_string())?;
|
||||
self.word_nbsp(&header.abi.to_string())?;
|
||||
}
|
||||
|
||||
self.s.word("fn")
|
||||
|
@ -3181,10 +3186,20 @@ mod tests {
|
|||
variadic: false
|
||||
};
|
||||
let generics = ast::Generics::default();
|
||||
assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal,
|
||||
ast::Constness::NotConst,
|
||||
abba_ident, &generics),
|
||||
"fn abba()");
|
||||
assert_eq!(
|
||||
fun_to_string(
|
||||
&decl,
|
||||
ast::FnHeader {
|
||||
unsafety: ast::Unsafety::Normal,
|
||||
constness: codemap::dummy_spanned(ast::Constness::NotConst),
|
||||
asyncness: ast::IsAsync::NotAsync,
|
||||
abi: Abi::Rust,
|
||||
},
|
||||
abba_ident,
|
||||
&generics
|
||||
),
|
||||
"fn abba()"
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -124,11 +124,25 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
|
|||
|
||||
if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
|
||||
match i.node {
|
||||
ast::ItemKind::Fn(_, ast::Unsafety::Unsafe, _, _, _, _) => {
|
||||
ast::ItemKind::Fn(_, header, _, _) => {
|
||||
if header.unsafety == ast::Unsafety::Unsafe {
|
||||
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.is_async() {
|
||||
let diag = self.cx.span_diagnostic;
|
||||
diag.span_fatal(
|
||||
i.span,
|
||||
"async functions cannot be used for tests"
|
||||
).raise();
|
||||
}
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
|
||||
debug!("this is a test function");
|
||||
let test = Test {
|
||||
span: i.span,
|
||||
|
@ -141,8 +155,6 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
|
|||
self.cx.testfns.push(test);
|
||||
self.tests.push(i.ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut item = i.into_inner();
|
||||
// We don't want to recurse into anything other than mods, since
|
||||
|
@ -338,7 +350,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
|
|||
fn has_test_signature(_cx: &TestCtxt, i: &ast::Item) -> HasTestSignature {
|
||||
let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic");
|
||||
match i.node {
|
||||
ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
|
||||
ast::ItemKind::Fn(ref decl, _, ref generics, _) => {
|
||||
// If the termination trait is active, the compiler will check that the output
|
||||
// type implements the `Termination` trait as `libtest` enforces that.
|
||||
let has_output = match decl.output {
|
||||
|
@ -396,7 +408,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
|
|||
|
||||
fn has_bench_signature(_cx: &TestCtxt, i: &ast::Item) -> bool {
|
||||
match i.node {
|
||||
ast::ItemKind::Fn(ref decl, _, _, _, _, _) => {
|
||||
ast::ItemKind::Fn(ref decl, _, _, _) => {
|
||||
// NB: inadequate check, but we're running
|
||||
// well before resolve, can't get too deep.
|
||||
decl.inputs.len() == 1
|
||||
|
@ -537,9 +549,7 @@ fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> {
|
|||
let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![]));
|
||||
let main_body = ecx.block(sp, vec![call_test_main]);
|
||||
let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)),
|
||||
ast::Unsafety::Normal,
|
||||
dummy_spanned(ast::Constness::NotConst),
|
||||
::rustc_target::spec::abi::Abi::Rust,
|
||||
ast::FnHeader::default(),
|
||||
ast::Generics::default(),
|
||||
main_body);
|
||||
P(ast::Item {
|
||||
|
|
|
@ -277,6 +277,7 @@ pub enum ExprPrecedence {
|
|||
Block,
|
||||
Catch,
|
||||
Struct,
|
||||
Async,
|
||||
}
|
||||
|
||||
impl PartialOrd for ExprPrecedence {
|
||||
|
@ -346,6 +347,7 @@ impl ExprPrecedence {
|
|||
ExprPrecedence::Match |
|
||||
ExprPrecedence::Block |
|
||||
ExprPrecedence::Catch |
|
||||
ExprPrecedence::Async |
|
||||
ExprPrecedence::Struct => PREC_PAREN,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,17 +23,15 @@
|
|||
//! instance, a walker looking for item names in a module will miss all of
|
||||
//! those that are created by the expansion of a macro.
|
||||
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use ast::*;
|
||||
use syntax_pos::Span;
|
||||
use codemap::Spanned;
|
||||
use parse::token::Token;
|
||||
use tokenstream::{TokenTree, TokenStream};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum FnKind<'a> {
|
||||
/// fn foo() or extern "Abi" fn foo()
|
||||
ItemFn(Ident, Unsafety, Spanned<Constness>, Abi, &'a Visibility, &'a Block),
|
||||
ItemFn(Ident, FnHeader, &'a Visibility, &'a Block),
|
||||
|
||||
/// fn foo(&self)
|
||||
Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a Block),
|
||||
|
@ -235,10 +233,10 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
|||
visitor.visit_ty(typ);
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
ItemKind::Fn(ref declaration, unsafety, constness, abi, ref generics, ref body) => {
|
||||
ItemKind::Fn(ref declaration, header, ref generics, ref body) => {
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_fn(FnKind::ItemFn(item.ident, unsafety,
|
||||
constness, abi, &item.vis, body),
|
||||
visitor.visit_fn(FnKind::ItemFn(item.ident, header,
|
||||
&item.vis, body),
|
||||
declaration,
|
||||
item.span,
|
||||
item.id)
|
||||
|
@ -544,7 +542,7 @@ pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl
|
|||
where V: Visitor<'a>,
|
||||
{
|
||||
match kind {
|
||||
FnKind::ItemFn(_, _, _, _, _, body) => {
|
||||
FnKind::ItemFn(_, _, _, body) => {
|
||||
walk_fn_decl(visitor, declaration);
|
||||
visitor.visit_block(body);
|
||||
}
|
||||
|
@ -737,7 +735,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||
visitor.visit_expr(subexpression);
|
||||
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),
|
||||
function_declaration,
|
||||
expression.span,
|
||||
|
@ -747,6 +745,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||
walk_list!(visitor, visit_label, opt_label);
|
||||
visitor.visit_block(block);
|
||||
}
|
||||
ExprKind::Async(_, _, ref body) => {
|
||||
visitor.visit_block(body);
|
||||
}
|
||||
ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
|
||||
visitor.visit_expr(left_hand_expression);
|
||||
visitor.visit_expr(right_hand_expression);
|
||||
|
|
|
@ -197,7 +197,7 @@ use syntax::ast::{VariantData, GenericParamKind, GenericArg};
|
|||
use syntax::attr;
|
||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::codemap::{self, dummy_spanned, respan};
|
||||
use syntax::codemap::{self, respan};
|
||||
use syntax::util::move_map::MoveMap;
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::{Symbol, keywords};
|
||||
|
@ -971,10 +971,10 @@ impl<'a> MethodDef<'a> {
|
|||
defaultness: ast::Defaultness::Final,
|
||||
ident: method_ident,
|
||||
node: ast::ImplItemKind::Method(ast::MethodSig {
|
||||
abi,
|
||||
unsafety,
|
||||
constness:
|
||||
dummy_spanned(ast::Constness::NotConst),
|
||||
header: ast::FnHeader {
|
||||
unsafety, abi,
|
||||
..ast::FnHeader::default()
|
||||
},
|
||||
decl: fn_decl,
|
||||
},
|
||||
body_block),
|
||||
|
|
|
@ -493,12 +493,14 @@ pub enum CompilerDesugaringKind {
|
|||
/// to an `existential type Foo: Trait;` + replacing the
|
||||
/// `impl Trait` with `Foo`.
|
||||
ExistentialReturnType,
|
||||
Async,
|
||||
}
|
||||
|
||||
impl CompilerDesugaringKind {
|
||||
pub fn as_symbol(&self) -> Symbol {
|
||||
use CompilerDesugaringKind::*;
|
||||
let s = match *self {
|
||||
Async => "async",
|
||||
DotFill => "...",
|
||||
QuestionMark => "?",
|
||||
Catch => "do catch",
|
||||
|
|
|
@ -16,6 +16,6 @@ impl Foo {
|
|||
fn foo() {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
} //~ ERROR expected one of `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`
|
||||
} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -14,6 +14,6 @@ struct Foo;
|
|||
|
||||
impl Foo {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
} //~ ERROR expected one of `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`
|
||||
} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -15,4 +15,4 @@ struct S;
|
|||
impl S {
|
||||
static fn f() {}
|
||||
}
|
||||
//~^^ ERROR expected one of `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`
|
||||
//~^^ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
macro_rules! bah {
|
||||
($a:expr) => ($a)
|
||||
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `2`
|
||||
//~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found `2`
|
||||
}
|
||||
|
||||
trait bar {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
trait Foo {
|
||||
pub const Foo: u32;
|
||||
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub`
|
||||
//~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
trait Foo {
|
||||
pub type Foo;
|
||||
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub`
|
||||
//~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
trait Foo {
|
||||
pub fn foo();
|
||||
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub`
|
||||
//~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -124,6 +124,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P<Expr>)) {
|
|||
});
|
||||
iter_exprs(depth - 1, &mut |e| g(
|
||||
ExprKind::Closure(CaptureBy::Value,
|
||||
IsAsync::NotAsync,
|
||||
Movability::Movable,
|
||||
decl.clone(),
|
||||
e,
|
||||
|
|
152
src/test/run-pass/async-await.rs
Normal file
152
src/test/run-pass/async-await.rs
Normal file
|
@ -0,0 +1,152 @@
|
|||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe async fn unsafe_async_fn(x: u8) -> u8 {
|
||||
await!(wake_and_yield_once());
|
||||
x
|
||||
}
|
||||
|
||||
struct Foo;
|
||||
|
||||
trait Bar {
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
impl Foo {
|
||||
async fn async_method(x: u8) -> u8 {
|
||||
unsafe {
|
||||
await!(unsafe_async_fn(x))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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[E0725]: 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 with identical lifetimes
|
||||
|
||||
error[E0726]: 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, E0725, E0726.
|
||||
For more information about an error, try `rustc --explain E0106`.
|
|
@ -38,11 +38,11 @@ LL | L = M; //~ ERROR missing
|
|||
LL | | Z = { 2 + 3 }; //~ ERROR expected one of
|
||||
| |____^ missing `fn`, `type`, or `const`
|
||||
|
||||
error: expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
|
||||
error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
|
||||
--> $DIR/issue-40006.rs:23:18
|
||||
|
|
||||
LL | Z = { 2 + 3 }; //~ ERROR expected one of
|
||||
| ^ expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}` here
|
||||
| ^ expected one of 7 possible tokens here
|
||||
|
||||
error: expected one of `!` or `::`, found `(`
|
||||
--> $DIR/issue-40006.rs:24:9
|
||||
|
|
|
@ -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!(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
|
||||
module::async(); //~ ERROR expected identifier, found reserved keyword `async`
|
||||
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`
|
||||
| ^^^^^
|
||||
|
||||
error: expected expression, found reserved keyword `async`
|
||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:28:22
|
||||
error: expected one of `move`, `|`, or `||`, found `<eof>`
|
||||
--> <passes_ident macros>:1:22
|
||||
|
|
||||
LL | if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
|
||||
| ^^^^^ expected expression
|
||||
LL | ( $ i : ident ) => ( $ i )
|
||||
| ^^^ expected one of `move`, `|`, or `||` here
|
||||
|
||||
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!(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
|
||||
module::async(); //~ ERROR expected identifier, found reserved keyword `async`
|
||||
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`
|
||||
| ^^^^^
|
||||
|
||||
error: expected expression, found reserved keyword `async`
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:28:22
|
||||
error: expected one of `move`, `|`, or `||`, found `<eof>`
|
||||
--> <passes_ident macros>:1:22
|
||||
|
|
||||
LL | if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
|
||||
| ^^^^^ expected expression
|
||||
LL | ( $ i : ident ) => ( $ i )
|
||||
| ^^^ expected one of `move`, `|`, or `||` here
|
||||
|
||||
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[E0727]: `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 E0727`.
|
|
@ -1,8 +1,8 @@
|
|||
error: expected one of `(`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found `}`
|
||||
error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found `}`
|
||||
--> $DIR/issue-41155.rs:13:1
|
||||
|
|
||||
LL | pub
|
||||
| - expected one of 7 possible tokens here
|
||||
| - expected one of 8 possible tokens here
|
||||
LL | } //~ ERROR expected one of
|
||||
| ^ unexpected token
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue