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:
commit
cfb6d84720
35 changed files with 744 additions and 478 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue