Auto merge of #64999 - nikomatsakis:issue-60424-async-return-inference, r=cramertj

extract expected return type for async fn generators

Fixes #60424

cc @Centril, I know you've been eager to see this fixed.

r? @cramertj
This commit is contained in:
bors 2019-10-03 12:19:21 +00:00
commit cfb6d84720
35 changed files with 744 additions and 478 deletions

View file

@ -89,9 +89,14 @@ impl LoweringContext<'_> {
hir::MatchSource::Normal,
),
ExprKind::Async(capture_clause, closure_node_id, ref block) => {
self.make_async_expr(capture_clause, closure_node_id, None, block.span, |this| {
this.with_new_scopes(|this| this.lower_block_expr(block))
})
self.make_async_expr(
capture_clause,
closure_node_id,
None,
block.span,
hir::AsyncGeneratorKind::Block,
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
)
}
ExprKind::Await(ref expr) => self.lower_expr_await(e.span, expr),
ExprKind::Closure(
@ -457,6 +462,7 @@ impl LoweringContext<'_> {
closure_node_id: NodeId,
ret_ty: Option<AstP<Ty>>,
span: Span,
async_gen_kind: hir::AsyncGeneratorKind,
body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
) -> hir::ExprKind {
let capture_clause = self.lower_capture_clause(capture_clause);
@ -470,7 +476,7 @@ impl LoweringContext<'_> {
};
let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None);
let body_id = self.lower_fn_body(&ast_decl, |this| {
this.generator_kind = Some(hir::GeneratorKind::Async);
this.generator_kind = Some(hir::GeneratorKind::Async(async_gen_kind));
body(this)
});
@ -522,7 +528,7 @@ impl LoweringContext<'_> {
/// ```
fn lower_expr_await(&mut self, await_span: Span, expr: &Expr) -> hir::ExprKind {
match self.generator_kind {
Some(hir::GeneratorKind::Async) => {},
Some(hir::GeneratorKind::Async(_)) => {},
Some(hir::GeneratorKind::Gen) |
None => {
let mut err = struct_span_err!(
@ -727,7 +733,7 @@ impl LoweringContext<'_> {
Movability::Static => hir::GeneratorMovability::Static,
})
},
Some(hir::GeneratorKind::Async) => {
Some(hir::GeneratorKind::Async(_)) => {
bug!("non-`async` closure body turned `async` during lowering");
},
None => {
@ -786,10 +792,12 @@ impl LoweringContext<'_> {
None
};
let async_body = this.make_async_expr(
capture_clause, closure_id, async_ret_ty, body.span,
|this| {
this.with_new_scopes(|this| this.lower_expr(body))
}
capture_clause,
closure_id,
async_ret_ty,
body.span,
hir::AsyncGeneratorKind::Closure,
|this| this.with_new_scopes(|this| this.lower_expr(body)),
);
this.expr(fn_decl_span, async_body, ThinVec::new())
});
@ -1005,7 +1013,7 @@ impl LoweringContext<'_> {
fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind {
match self.generator_kind {
Some(hir::GeneratorKind::Gen) => {},
Some(hir::GeneratorKind::Async) => {
Some(hir::GeneratorKind::Async(_)) => {
span_err!(
self.sess,
span,

View file

@ -1222,7 +1222,11 @@ impl LoweringContext<'_> {
}
let async_expr = this.make_async_expr(
CaptureBy::Value, closure_id, None, body.span,
CaptureBy::Value,
closure_id,
None,
body.span,
hir::AsyncGeneratorKind::Fn,
|this| {
// Create a block from the user's function body:
let user_body = this.lower_block_expr(body);

View file

@ -1362,21 +1362,49 @@ impl Body {
}
/// The type of source expression that caused this generator to be created.
// Not `IsAsync` because we want to eventually add support for `AsyncGen`
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable,
RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum GeneratorKind {
/// An `async` block or function.
Async,
/// An explicit `async` block or the body of an async function.
Async(AsyncGeneratorKind),
/// A generator literal created via a `yield` inside a closure.
Gen,
}
impl fmt::Display for GeneratorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GeneratorKind::Async(k) => fmt::Display::fmt(k, f),
GeneratorKind::Gen => f.write_str("generator"),
}
}
}
/// In the case of a generator created as part of an async construct,
/// which kind of async construct caused it to be created?
///
/// This helps error messages but is also used to drive coercions in
/// type-checking (see #60424).
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable,
RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum AsyncGeneratorKind {
/// An explicit `async` block written by the user.
Block,
/// An explicit `async` block written by the user.
Closure,
/// The `async` block generated as the body of an async function.
Fn,
}
impl fmt::Display for AsyncGeneratorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
GeneratorKind::Async => "`async` object",
GeneratorKind::Gen => "generator",
AsyncGeneratorKind::Block => "`async` block",
AsyncGeneratorKind::Closure => "`async` closure body",
AsyncGeneratorKind::Fn => "`async fn` body",
})
}
}
@ -1758,6 +1786,7 @@ pub struct Destination {
pub enum GeneratorMovability {
/// May contain self-references, `!Unpin`.
Static,
/// Must not contain self-references, `Unpin`.
Movable,
}

View file

@ -1319,6 +1319,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
/// Resolve any type variables found in `value` -- but only one
/// level. So, if the variable `?X` is bound to some type
/// `Foo<?Y>`, then this would return `Foo<?Y>` (but `?Y` may
/// itself be bound to a type).
///
/// Useful when you only need to inspect the outermost level of
/// the type and don't care about nested types (or perhaps you
/// will be resolving them as well, e.g. in a loop).
pub fn shallow_resolve<T>(&self, value: T) -> T
where
T: TypeFoldable<'tcx>,
@ -1579,6 +1587,9 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> {
ShallowResolver { infcx }
}
/// If `typ` is a type variable of some kind, resolve it one level
/// (but do not resolve types found in the result). If `typ` is
/// not a type variable, just return it unmodified.
pub fn shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> {
match typ.kind {
ty::Infer(ty::TyVar(v)) => {