Skip to content

Commit 1533923

Browse files
author
Without Boats
committed
Lower the return type of async functions properly.
1 parent 8319f3d commit 1533923

File tree

10 files changed

+174
-26
lines changed

10 files changed

+174
-26
lines changed

src/librustc/hir/lowering.rs

+141-15
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,14 @@ enum AnonymousLifetimeMode {
296296
PassThrough,
297297
}
298298

299+
trait FnRetTransform {
300+
fn lower(&self, ctx: &mut LoweringContext, output: &FunctionRetTy, impl_trait_context: ImplTraitContext) -> hir::FunctionRetTy;
301+
}
302+
303+
struct NonAsyncRet;
304+
struct AsyncClosureRet;
305+
struct AsyncFunctionRet;
306+
299307
impl<'a> LoweringContext<'a> {
300308
fn lower_crate(mut self, c: &Crate) -> hir::Crate {
301309
/// Full-crate AST visitor that inserts into a fresh
@@ -1050,7 +1058,7 @@ impl<'a> LoweringContext<'a> {
10501058
),
10511059
unsafety: this.lower_unsafety(f.unsafety),
10521060
abi: f.abi,
1053-
decl: this.lower_fn_decl(&f.decl, None, false),
1061+
decl: this.lower_fn_decl(&f.decl, None, false, &NonAsyncRet),
10541062
arg_names: this.lower_fn_args_to_names(&f.decl),
10551063
}))
10561064
},
@@ -1729,7 +1737,121 @@ impl<'a> LoweringContext<'a> {
17291737
decl: &FnDecl,
17301738
fn_def_id: Option<DefId>,
17311739
impl_trait_return_allow: bool,
1740+
fn_ret_transform: &FnRetTransform,
17321741
) -> P<hir::FnDecl> {
1742+
// For non async functions, the return type is lowered in a straightforward way
1743+
impl FnRetTransform for NonAsyncRet {
1744+
fn lower(&self, ctx: &mut LoweringContext, output: &FunctionRetTy, impl_trait_context: ImplTraitContext) -> hir::FunctionRetTy {
1745+
match output {
1746+
FunctionRetTy::Ty(ty) => hir::Return(ctx.lower_ty(ty, impl_trait_context)),
1747+
FunctionRetTy::Default(span) => hir::DefaultReturn(*span),
1748+
}
1749+
}
1750+
}
1751+
1752+
// For async closures:
1753+
// - If the return type is omitted, a straightforward lowering is performed
1754+
// - If the return type is explicit, given a return type T, it is lowered to
1755+
// ::std::raw::GenFuture<_, T>
1756+
impl FnRetTransform for AsyncClosureRet {
1757+
fn lower(&self, ctx: &mut LoweringContext, output: &FunctionRetTy, impl_trait_context: ImplTraitContext) -> hir::FunctionRetTy {
1758+
match output {
1759+
FunctionRetTy::Ty(ty) => {
1760+
let inner_ty = ctx.lower_ty(ty, impl_trait_context);
1761+
let span = inner_ty.span;
1762+
let hir::Path { def, segments, .. } = ctx.std_path(span, &["raw", "GenFuture"], false);
1763+
let LoweredNodeId { node_id, hir_id } = ctx.next_id();
1764+
let gen_future_path = hir::Path {
1765+
segments: segments.map_slice(|mut v| {
1766+
v.last_mut().unwrap().parameters = Some(P(hir::PathParameters {
1767+
lifetimes: hir_vec![],
1768+
bindings: hir_vec![],
1769+
types: hir_vec![
1770+
P(hir::Ty {
1771+
id: node_id,
1772+
node: hir::TyInfer,
1773+
hir_id, span,
1774+
}),
1775+
inner_ty,
1776+
],
1777+
parenthesized: false,
1778+
}));
1779+
v
1780+
}),
1781+
def, span
1782+
};
1783+
1784+
let LoweredNodeId { node_id, hir_id } = ctx.next_id();
1785+
hir::Return(P(hir::Ty {
1786+
id: node_id,
1787+
node: hir::TyPath(hir::QPath::Resolved(None, P(gen_future_path))),
1788+
hir_id, span,
1789+
}))
1790+
}
1791+
FunctionRetTy::Default(span) => hir::DefaultReturn(*span),
1792+
}
1793+
}
1794+
}
1795+
1796+
// For async functions the return type is lowered to impl ::std::future::Future<Output = T>
1797+
impl FnRetTransform for AsyncFunctionRet {
1798+
fn lower(&self, ctx: &mut LoweringContext, output: &FunctionRetTy, impl_trait_context: ImplTraitContext) -> hir::FunctionRetTy {
1799+
let inner_ty = match output {
1800+
FunctionRetTy::Ty(ty) => ctx.lower_ty(ty, impl_trait_context),
1801+
FunctionRetTy::Default(span) => {
1802+
let LoweredNodeId { node_id, hir_id } = ctx.next_id();
1803+
P(hir::Ty {
1804+
id: node_id,
1805+
hir_id: hir_id,
1806+
node: hir::TyTup(hir_vec![]),
1807+
span: *span,
1808+
})
1809+
}
1810+
};
1811+
let span = inner_ty.span;
1812+
let hir::Path { def, segments, .. } = ctx.std_path(span, &["future", "Future"], false);
1813+
let future_path = hir::Path {
1814+
segments: segments.map_slice(|mut v| {
1815+
v.last_mut().unwrap().parameters = Some(P(hir::PathParameters {
1816+
lifetimes: hir_vec![],
1817+
types: hir_vec![],
1818+
bindings: hir_vec![hir::TypeBinding {
1819+
name: ctx.str_to_ident("Output"),
1820+
ty: inner_ty,
1821+
id: ctx.next_id().node_id,
1822+
span,
1823+
}],
1824+
parenthesized: false,
1825+
}));
1826+
v
1827+
}),
1828+
def, span
1829+
};
1830+
let LoweredNodeId { hir_id, node_id } = ctx.next_id();
1831+
hir::Return(P(hir::Ty {
1832+
id: node_id,
1833+
node: hir::TyImplTraitExistential(hir::ExistTy {
1834+
generics: hir::Generics::empty(),
1835+
bounds: hir_vec![hir::TyParamBound::TraitTyParamBound(hir::PolyTraitRef {
1836+
trait_ref: hir::TraitRef {
1837+
path: future_path,
1838+
ref_id: ctx.next_id().node_id,
1839+
},
1840+
bound_generic_params: hir_vec![],
1841+
span,
1842+
}, hir::TraitBoundModifier::None)],
1843+
}, hir_vec![]),
1844+
hir_id, span,
1845+
}))
1846+
}
1847+
}
1848+
1849+
let output_impl_trait_context = if fn_def_id.is_some() && impl_trait_return_allow {
1850+
ImplTraitContext::Existential
1851+
} else {
1852+
ImplTraitContext::Disallowed
1853+
};
1854+
17331855
// NOTE: The two last parameters here have to do with impl Trait. If fn_def_id is Some,
17341856
// then impl Trait arguments are lowered into generic parameters on the given
17351857
// fn_def_id, otherwise impl Trait is disallowed. (for now)
@@ -1748,15 +1870,7 @@ impl<'a> LoweringContext<'a> {
17481870
}
17491871
})
17501872
.collect(),
1751-
output: match decl.output {
1752-
FunctionRetTy::Ty(ref ty) => match fn_def_id {
1753-
Some(_) if impl_trait_return_allow => {
1754-
hir::Return(self.lower_ty(ty, ImplTraitContext::Existential))
1755-
}
1756-
_ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
1757-
},
1758-
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
1759-
},
1873+
output: fn_ret_transform.lower(self, &decl.output, output_impl_trait_context),
17601874
variadic: decl.variadic,
17611875
has_implicit_self: decl.inputs.get(0).map_or(false, |arg| match arg.ty.node {
17621876
TyKind::ImplicitSelf => true,
@@ -2201,11 +2315,15 @@ impl<'a> LoweringContext<'a> {
22012315
let body = this.lower_block(body, false);
22022316
this.expr_block(body, ThinVec::new())
22032317
});
2318+
let fn_ret_transform: &FnRetTransform = match header.asyncness {
2319+
IsAsync::Async => &AsyncFunctionRet,
2320+
IsAsync::NotAsync => &NonAsyncRet,
2321+
};
22042322
let (generics, fn_decl) = this.add_in_band_defs(
22052323
generics,
22062324
fn_def_id,
22072325
AnonymousLifetimeMode::PassThrough,
2208-
|this| this.lower_fn_decl(decl, Some(fn_def_id), true),
2326+
|this| this.lower_fn_decl(decl, Some(fn_def_id), true, fn_ret_transform),
22092327
);
22102328

22112329
hir::ItemFn(
@@ -2721,7 +2839,7 @@ impl<'a> LoweringContext<'a> {
27212839
|this| {
27222840
(
27232841
// Disallow impl Trait in foreign items
2724-
this.lower_fn_decl(fdec, None, false),
2842+
this.lower_fn_decl(fdec, None, false, &NonAsyncRet),
27252843
this.lower_fn_args_to_names(fdec),
27262844
)
27272845
},
@@ -2747,9 +2865,13 @@ impl<'a> LoweringContext<'a> {
27472865
fn_def_id: DefId,
27482866
impl_trait_return_allow: bool,
27492867
) -> hir::MethodSig {
2868+
let fn_ret_transform: &FnRetTransform = match sig.header.asyncness {
2869+
IsAsync::Async => &AsyncFunctionRet,
2870+
IsAsync::NotAsync => &NonAsyncRet,
2871+
};
27502872
hir::MethodSig {
27512873
header: self.lower_fn_header(sig.header),
2752-
decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow),
2874+
decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow, fn_ret_transform),
27532875
}
27542876
}
27552877

@@ -3074,7 +3196,7 @@ impl<'a> LoweringContext<'a> {
30743196
arms.iter().map(|x| self.lower_arm(x)).collect(),
30753197
hir::MatchSource::Normal,
30763198
),
3077-
ExprKind::Closure(capture_clause, movability, ref decl, ref body, fn_decl_span) => {
3199+
ExprKind::Closure(capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span) => {
30783200
self.with_new_scopes(|this| {
30793201
this.with_parent_def(e.id, |this| {
30803202
let mut is_generator = false;
@@ -3108,9 +3230,13 @@ impl<'a> LoweringContext<'a> {
31083230
}
31093231
None
31103232
};
3233+
let fn_ret_transform: &FnRetTransform = match asyncness {
3234+
IsAsync::Async => &AsyncClosureRet,
3235+
IsAsync::NotAsync => &NonAsyncRet,
3236+
};
31113237
hir::ExprClosure(
31123238
this.lower_capture_clause(capture_clause),
3113-
this.lower_fn_decl(decl, None, false),
3239+
this.lower_fn_decl(decl, None, false, fn_ret_transform),
31143240
body_id,
31153241
fn_decl_span,
31163242
generator_option,

src/librustc_resolve/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
790790
FnKind::Method(_, _, _, _) => {
791791
TraitOrImplItemRibKind
792792
}
793-
FnKind::Closure(_) => ClosureRibKind(node_id),
793+
FnKind::Closure(..) => ClosureRibKind(node_id),
794794
};
795795

796796
// Create a value rib for the function.
@@ -816,7 +816,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
816816
FnKind::Method(.., body) => {
817817
self.visit_block(body);
818818
}
819-
FnKind::Closure(body) => {
819+
FnKind::Closure(_, body) => {
820820
self.visit_expr(body);
821821
}
822822
};

src/librustc_save_analysis/dump_visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
15491549
}
15501550
}
15511551
}
1552-
ast::ExprKind::Closure(_, _, ref decl, ref body, _fn_decl_span) => {
1552+
ast::ExprKind::Closure(_, _, _, ref decl, ref body, _fn_decl_span) => {
15531553
let mut id = String::from("$");
15541554
id.push_str(&ex.id.to_string());
15551555

src/libsyntax/ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ pub enum ExprKind {
11331133
/// A closure (for example, `move |a, b, c| a + b + c`)
11341134
///
11351135
/// The final span is the span of the argument block `|...|`
1136-
Closure(CaptureBy, Movability, P<FnDecl>, P<Expr>, Span),
1136+
Closure(CaptureBy, IsAsync, Movability, P<FnDecl>, P<Expr>, Span),
11371137
/// A block (`'label: { ... }`)
11381138
Block(P<Block>, Option<Label>),
11391139
/// A catch block (`catch { ... }`)

src/libsyntax/ext/build.rs

+2
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
914914
fn_decl_span: Span) // span of the `|...|` part
915915
-> P<ast::Expr> {
916916
self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref,
917+
ast::IsAsync::NotAsync,
917918
ast::Movability::Movable,
918919
fn_decl,
919920
body,
@@ -934,6 +935,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
934935
// the entire lambda body. Probably we should extend the API
935936
// here, but that's not entirely clear.
936937
self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref,
938+
ast::IsAsync::NotAsync,
937939
ast::Movability::Movable,
938940
fn_decl,
939941
body,

src/libsyntax/fold.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1265,8 +1265,9 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
12651265
ExprKind::Match(folder.fold_expr(expr),
12661266
arms.move_map(|x| folder.fold_arm(x)))
12671267
}
1268-
ExprKind::Closure(capture_clause, movability, decl, body, span) => {
1268+
ExprKind::Closure(capture_clause, asyncness, movability, decl, body, span) => {
12691269
ExprKind::Closure(capture_clause,
1270+
asyncness,
12701271
movability,
12711272
folder.fold_fn_decl(decl),
12721273
folder.fold_expr(body),

src/libsyntax/parse/parser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3312,7 +3312,7 @@ impl<'a> Parser<'a> {
33123312

33133313
Ok(self.mk_expr(
33143314
lo.to(body.span),
3315-
ExprKind::Closure(capture_clause, movability, decl, body, lo.to(decl_hi)),
3315+
ExprKind::Closure(capture_clause, IsAsync::NotAsync, movability, decl, body, lo.to(decl_hi)),
33163316
attrs))
33173317
}
33183318

src/libsyntax/print/pprust.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -2158,8 +2158,9 @@ impl<'a> State<'a> {
21582158
}
21592159
self.bclose_(expr.span, INDENT_UNIT)?;
21602160
}
2161-
ast::ExprKind::Closure(capture_clause, movability, ref decl, ref body, _) => {
2161+
ast::ExprKind::Closure(capture_clause, asyncness, movability, ref decl, ref body, _) => {
21622162
self.print_movability(movability)?;
2163+
self.print_asyncness(asyncness)?;
21632164
self.print_capture_clause(capture_clause)?;
21642165

21652166
self.print_fn_block_args(decl)?;
@@ -2793,6 +2794,14 @@ impl<'a> State<'a> {
27932794
}
27942795
}
27952796

2797+
pub fn print_asyncness(&mut self, asyncness: ast::IsAsync)
2798+
-> io::Result<()> {
2799+
match asyncness {
2800+
ast::IsAsync::Async => self.word_space("async"),
2801+
ast::IsAsync::NotAsync => Ok(()),
2802+
}
2803+
}
2804+
27962805
pub fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy)
27972806
-> io::Result<()> {
27982807
match capture_clause {

src/libsyntax/ptr.rs

+10
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,16 @@ impl<T: 'static> P<T> {
9595
}
9696
}
9797

98+
impl<T: 'static> P<[T]> {
99+
pub fn map_slice<F>(self, f: F) -> P<[T]> where
100+
F: FnOnce(Vec<T>) -> Vec<T>
101+
{
102+
P {
103+
ptr: f(self.ptr.into()).into(),
104+
}
105+
}
106+
}
107+
98108
impl<T: ?Sized> Deref for P<T> {
99109
type Target = T;
100110

src/libsyntax/visit.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub enum FnKind<'a> {
3737
Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a Block),
3838

3939
/// |x, y| body
40-
Closure(&'a Expr),
40+
Closure(IsAsync, &'a Expr),
4141
}
4242

4343
/// Each method of the Visitor trait is a hook to be potentially
@@ -552,7 +552,7 @@ pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl
552552
walk_fn_decl(visitor, declaration);
553553
visitor.visit_block(body);
554554
}
555-
FnKind::Closure(body) => {
555+
FnKind::Closure(_, body) => {
556556
walk_fn_decl(visitor, declaration);
557557
visitor.visit_expr(body);
558558
}
@@ -733,8 +733,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
733733
visitor.visit_expr(subexpression);
734734
walk_list!(visitor, visit_arm, arms);
735735
}
736-
ExprKind::Closure(_, _, ref function_declaration, ref body, _decl_span) => {
737-
visitor.visit_fn(FnKind::Closure(body),
736+
ExprKind::Closure(_, is_async, _, ref function_declaration, ref body, _decl_span) => {
737+
visitor.visit_fn(FnKind::Closure(is_async, body),
738738
function_declaration,
739739
expression.span,
740740
expression.id)

0 commit comments

Comments
 (0)