Skip to content

Commit

Permalink
Auto merge of #104833 - Swatinem:async-identity-future, r=compiler-er…
Browse files Browse the repository at this point in the history
…rors

Remove `identity_future` indirection

This was previously needed because the indirection used to hide some unexplained lifetime errors, which it turned out were related to the `min_choice` algorithm.

Removing the indirection also solves a couple of cycle errors, large moves and makes async blocks support the `#[track_caller]`annotation.

Fixes #104826.
  • Loading branch information
bors committed Mar 14, 2023
2 parents 0058748 + 9f03cfc commit 669e751
Show file tree
Hide file tree
Showing 32 changed files with 145 additions and 357 deletions.
64 changes: 27 additions & 37 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
ensure_sufficient_stack(|| {
match &e.kind {
// Paranthesis expression does not have a HirId and is handled specially.
// Parenthesis expression does not have a HirId and is handled specially.
ExprKind::Paren(ex) => {
let mut ex = self.lower_expr_mut(ex);
// Include parens in span, but only if it is a super-span.
Expand Down Expand Up @@ -63,6 +63,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::ForLoop(pat, head, body, opt_label) => {
return self.lower_expr_for(e, pat, head, body, *opt_label);
}
// Similarly, async blocks do not use `e.id` but rather `closure_node_id`.
ExprKind::Async(capture_clause, closure_node_id, block) => {
let hir_id = self.lower_node_id(*closure_node_id);
self.lower_attrs(hir_id, &e.attrs);
return self.make_async_expr(
*capture_clause,
hir_id,
*closure_node_id,
None,
e.span,
hir::AsyncGeneratorKind::Block,
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
);
}
_ => (),
}

Expand Down Expand Up @@ -173,15 +187,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
hir::MatchSource::Normal,
),
ExprKind::Async(capture_clause, closure_node_id, block) => self.make_async_expr(
*capture_clause,
hir_id,
*closure_node_id,
None,
e.span,
hir::AsyncGeneratorKind::Block,
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
),
ExprKind::Await(expr) => {
let dot_await_span = if expr.span.hi() < e.span.hi() {
let span_with_whitespace = self
Expand Down Expand Up @@ -315,7 +320,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
),
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),

ExprKind::Paren(_) | ExprKind::ForLoop(..) => unreachable!("already handled"),
ExprKind::Paren(_) | ExprKind::ForLoop(..) | ExprKind::Async(..) => {
unreachable!("already handled")
}

ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
};
Expand Down Expand Up @@ -577,9 +584,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
/// This results in:
///
/// ```text
/// std::future::identity_future(static move? |_task_context| -> <ret_ty> {
/// static move? |_task_context| -> <ret_ty> {
/// <body>
/// })
/// }
/// ```
pub(super) fn make_async_expr(
&mut self,
Expand All @@ -590,7 +597,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
span: Span,
async_gen_kind: hir::AsyncGeneratorKind,
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::ExprKind<'hir> {
) -> hir::Expr<'hir> {
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));

// Resume argument type: `ResumeTy`
Expand Down Expand Up @@ -655,13 +662,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
};

let hir_id = self.lower_node_id(closure_node_id);
let unstable_span =
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());

if self.tcx.features().closure_track_caller
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
{
let unstable_span =
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
self.lower_attrs(
hir_id,
&[Attribute {
Expand All @@ -680,22 +686,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
}

let generator = hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) };

// FIXME(swatinem):
// For some reason, the async block needs to flow through *any*
// call (like the identity function), as otherwise type and lifetime
// inference have a hard time figuring things out.
// Without this, we would get:
// E0720 in tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
// E0700 in tests/ui/self/self_lifetime-async.rs

// `future::identity_future`:
let identity_future =
self.expr_lang_item_path(unstable_span, hir::LangItem::IdentityFuture, None);

// `future::identity_future(generator)`:
hir::ExprKind::Call(self.arena.alloc(identity_future), arena_vec![self; generator])
hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) }
}

/// Desugar `<expr>.await` into:
Expand Down Expand Up @@ -1001,7 +992,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}

// Transform `async |x: u8| -> X { ... }` into
// `|x: u8| identity_future(|| -> X { ... })`.
// `|x: u8| || -> X { ... }`.
let body_id = this.lower_fn_body(&outer_decl, |this| {
let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
Expand All @@ -1010,16 +1001,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
None
};

let async_body = this.make_async_expr(
this.make_async_expr(
capture_clause,
closure_hir_id,
inner_closure_id,
async_ret_ty,
body.span,
hir::AsyncGeneratorKind::Closure,
|this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
);
this.expr(fn_decl_span, async_body)
)
});
body_id
});
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1180,7 +1180,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
},
);

(this.arena.alloc_from_iter(parameters), this.expr(body.span, async_expr))
(this.arena.alloc_from_iter(parameters), async_expr)
})
}

Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,6 @@ language_item_table! {
// FIXME(swatinem): the following lang items are used for async lowering and
// should become obsolete eventually.
ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None;
IdentityFuture, sym::identity_future, identity_future_fn, Target::Fn, GenericRequirement::None;
GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None;

Context, sym::Context, context, Target::Struct, GenericRequirement::None;
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let fn_decl_span = if hir.body(body).generator_kind
== Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure))
{
// Actually need to unwrap a few more layers of HIR to get to
// Actually need to unwrap one more layer of HIR to get to
// the _real_ closure...
let async_closure = hir.parent_id(hir.parent_id(parent_hir_id));
let async_closure = hir.parent_id(parent_hir_id);
if let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
..
Expand Down
7 changes: 1 addition & 6 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -924,12 +924,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir_id,
kind: hir::ExprKind::Closure(..),
..
}) if let Some(Node::Expr(&hir::Expr {
hir_id,
kind: hir::ExprKind::Call(..),
..
})) = self.tcx.hir().find_parent(hir_id) &&
let Some(Node::Item(&hir::Item {
}) if let Some(Node::Item(&hir::Item {
ident,
kind: hir::ItemKind::Fn(ref sig, ..),
..
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,6 @@ symbols! {
i64,
i8,
ident,
identity_future,
if_let,
if_let_guard,
if_while_or_patterns,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3033,8 +3033,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
};

let identity_future = tcx.require_lang_item(LangItem::IdentityFuture, None);

// Don't print the tuple of capture types
'print: {
if !is_upvar_tys_infer_tuple {
Expand All @@ -3047,12 +3045,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
None => err.note(&msg),
},
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
// Avoid printing the future from `core::future::identity_future`, it's not helpful
if tcx.parent(*def_id) == identity_future {
break 'print;
}

// If the previous type is `identity_future`, this is the future generated by the body of an async function.
// If the previous type is async fn, this is the future generated by the body of an async function.
// Avoid printing it twice (it was already printed in the `ty::Generator` arm below).
let is_future = tcx.ty_is_opaque_future(ty);
debug!(
Expand Down
6 changes: 1 addition & 5 deletions library/core/src/future/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,10 @@ pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
unsafe { &mut *cx.0.as_ptr().cast() }
}

// FIXME(swatinem): This fn is currently needed to work around shortcomings
// in type and lifetime inference.
// See the comment at the bottom of `LoweringContext::make_async_expr` and
// <https://github.com/rust-lang/rust/issues/104826>.
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
#[inline]
#[lang = "identity_future"]
#[cfg_attr(bootstrap, lang = "identity_future")]
pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
f
}
9 changes: 1 addition & 8 deletions src/tools/clippy/clippy_lints/src/manual_async_fn.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::match_function_call_with_def_id;
use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
use if_chain::if_chain;
use rustc_errors::Applicability;
Expand Down Expand Up @@ -175,16 +174,10 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
if_chain! {
if let Some(block_expr) = block.expr;
if let Some(args) = cx
.tcx
.lang_items()
.identity_future_fn()
.and_then(|def_id| match_function_call_with_def_id(cx, block_expr, def_id));
if args.len() == 1;
if let Expr {
kind: ExprKind::Closure(&Closure { body, .. }),
..
} = args[0];
} = block_expr;
let closure_body = cx.tcx.hir().body(body);
if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block));
then {
Expand Down
11 changes: 1 addition & 10 deletions src/tools/clippy/clippy_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1904,16 +1904,7 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool {

/// Peels away all the compiler generated code surrounding the body of an async function,
pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
if let ExprKind::Call(
_,
&[
Expr {
kind: ExprKind::Closure(&Closure { body, .. }),
..
},
],
) = body.value.kind
{
if let ExprKind::Closure(&Closure { body, .. }) = body.value.kind {
if let ExprKind::Block(
Block {
stmts: [],
Expand Down
6 changes: 1 addition & 5 deletions src/tools/clippy/tests/ui/author/blocks.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,7 @@ if let ExprKind::Block(block, None) = expr.kind
if let ExprKind::Closure(CaptureBy::Value, fn_decl, body_id, _, None) = expr.kind
&& let FnRetTy::DefaultReturn(_) = fn_decl.output
&& expr1 = &cx.tcx.hir().body(body_id).value
&& let ExprKind::Call(func, args) = expr1.kind
&& let ExprKind::Path(ref qpath) = func.kind
&& matches!(qpath, QPath::LangItem(LangItem::IdentityFuture, _))
&& args.len() == 1
&& let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = args[0].kind
&& let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = expr1.kind
&& let FnRetTy::DefaultReturn(_) = fn_decl1.output
&& expr2 = &cx.tcx.hir().body(body_id1).value
&& let ExprKind::Block(block, None) = expr2.kind
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
_0: GeneratorSavedTy {
ty: impl std::future::Future<Output = ()>,
source_info: SourceInfo {
span: $DIR/async_await.rs:15:8: 15:14 (#9),
span: $DIR/async_await.rs:15:8: 15:14 (#8),
scope: scope[0],
},
ignore_for_traits: false,
},
_1: GeneratorSavedTy {
ty: impl std::future::Future<Output = ()>,
source_info: SourceInfo {
span: $DIR/async_await.rs:16:8: 16:14 (#12),
span: $DIR/async_await.rs:16:8: 16:14 (#11),
scope: scope[0],
},
ignore_for_traits: false,
Expand Down
14 changes: 8 additions & 6 deletions tests/ui/async-await/generator-desc.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ error[E0308]: mismatched types
--> $DIR/generator-desc.rs:10:19
|
LL | fun(async {}, async {});
| -------- ^^^^^^^^
| | |
| | expected `async` block, found a different `async` block
| | arguments to this function are incorrect
| the expected `async` block
| --- -------- ^^^^^^^^ expected `async` block, found a different `async` block
| | |
| | the expected `async` block
| arguments to this function are incorrect
|
= note: expected `async` block `[async block@$DIR/generator-desc.rs:10:9: 10:17]`
found `async` block `[async block@$DIR/generator-desc.rs:10:19: 10:27]`
note: function defined here
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
--> $DIR/generator-desc.rs:8:4
|
LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
| ^^^ -----

error[E0308]: mismatched types
--> $DIR/generator-desc.rs:12:16
Expand Down
22 changes: 4 additions & 18 deletions tests/ui/async-await/large_moves.attribute.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
error: moving 10024 bytes
--> $DIR/large_moves.rs:13:13
--> $DIR/large_moves.rs:19:14
|
LL | let x = async {
| _____________^
LL | | let y = [0; 9999];
LL | | dbg!(y);
LL | | thing(&y).await;
LL | | dbg!(y);
LL | | };
| |_____^ value moved from here
LL | let z = (x, 42);
| ^ value moved from here
|
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
note: the lint level is defined here
Expand All @@ -17,14 +11,6 @@ note: the lint level is defined here
LL | #![deny(large_assignments)]
| ^^^^^^^^^^^^^^^^^

error: moving 10024 bytes
--> $DIR/large_moves.rs:19:14
|
LL | let z = (x, 42);
| ^ value moved from here
|
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`

error: moving 10024 bytes
--> $DIR/large_moves.rs:19:13
|
Expand All @@ -41,5 +27,5 @@ LL | let a = z.0;
|
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`

error: aborting due to 4 previous errors
error: aborting due to 3 previous errors

Loading

0 comments on commit 669e751

Please sign in to comment.