diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 1435957a5c142..09153c144ae80 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -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
}
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index ed86ef705649b..766909f5723b6 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -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,
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 6291e0eb11372..d6da2fce69a74 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -168,6 +168,7 @@ pub trait Resolver {
span: Span,
crate_root: Option<&str>,
components: &[&str],
+ params: Option
>,
is_value: bool,
) -> hir::Path;
}
@@ -449,7 +450,7 @@ impl<'a> LoweringContext<'a> {
}
}
- fn allocate_hir_id_counter(&mut self, owner: NodeId, debug: &T) {
+ fn allocate_hir_id_counter(&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(&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(&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,31 +1874,40 @@ 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