Skip to content

Commit

Permalink
Remove identity_future indirection
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Swatinem committed Mar 8, 2023
1 parent 64165aa commit 9f03cfc
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 @@ -182,15 +196,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 @@ -324,7 +329,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 @@ -586,9 +593,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 @@ -599,7 +606,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 @@ -664,13 +671,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 @@ -689,22 +695,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 @@ -1010,7 +1001,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 @@ -1019,16 +1010,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 @@ -928,12 +928,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 @@ -791,7 +791,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 @@ -3025,8 +3025,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 @@ -3039,12 +3037,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 9f03cfc

Please sign in to comment.