Skip to content

Commit 6c1fd72

Browse files
committed
Auto merge of #117703 - compiler-errors:recursive-async, r=lcnr
Support async recursive calls (as long as they have indirection) Before #101692, we stored coroutine witness types directly inside of the coroutine. That means that a coroutine could not contain itself (as a witness field) without creating a cycle in the type representation of the coroutine, which we detected with the `OpaqueTypeExpander`, which is used to detect cycles when expanding opaque types after that are inferred to contain themselves. After `-Zdrop-tracking-mir` was stabilized, we no longer store these generator witness fields directly, but instead behind a def-id based query. That means there is no technical obstacle in the compiler preventing coroutines from containing themselves per se, other than the fact that for a coroutine to have a non-infinite layout, it must contain itself wrapped in a layer of allocation indirection (like a `Box`). This means that it should be valid for this code to work: ``` async fn async_fibonacci(i: u32) -> u32 { if i == 0 || i == 1 { i } else { Box::pin(async_fibonacci(i - 1)).await + Box::pin(async_fibonacci(i - 2)).await } } ``` Whereas previously, you'd need to coerce the future to `Pin<Box<dyn Future<Output = ...>>` before `await`ing it, to prevent the async's desugared coroutine from containing itself across as await point. This PR does two things: 1. Only report an error if an opaque expansion cycle is detected *not* through coroutine witness fields. * Instead, if we find an opaque cycle through coroutine witness fields, we compute the layout of the coroutine. If that results in a cycle error, we report it as a recursive async fn. 4. Reworks the way we report layout errors having to do with coroutines, to make up for the diagnostic regressions introduced by (1.). We actually do even better now, pointing out the call sites of the recursion!
2 parents d03eb65 + da25510 commit 6c1fd72

File tree

6 files changed

+9
-19
lines changed

6 files changed

+9
-19
lines changed

clippy_lints/src/copies.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use rustc_errors::Applicability;
1212
use rustc_hir::def_id::DefIdSet;
1313
use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind};
1414
use rustc_lint::{LateContext, LateLintPass};
15-
use rustc_middle::query::Key;
1615
use rustc_session::impl_lint_pass;
1716
use rustc_span::hygiene::walk_chain;
1817
use rustc_span::source_map::SourceMap;
@@ -574,7 +573,7 @@ fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignore
574573
let caller_ty = cx.typeck_results().expr_ty(caller_expr);
575574
// Check if given type has inner mutability and was not set to ignored by the configuration
576575
let is_inner_mut_ty = is_interior_mut_ty(cx, caller_ty)
577-
&& !matches!(caller_ty.ty_adt_id(), Some(adt_id) if ignored_ty_ids.contains(&adt_id));
576+
&& !matches!(caller_ty.ty_adt_def(), Some(adt) if ignored_ty_ids.contains(&adt.did()));
578577

579578
is_inner_mut_ty
580579
|| caller_ty.is_mutable_ptr()

clippy_lints/src/methods/drain_collect.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use clippy_utils::ty::is_type_lang_item;
66
use rustc_errors::Applicability;
77
use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath};
88
use rustc_lint::LateContext;
9-
use rustc_middle::query::Key;
109
use rustc_middle::ty;
1110
use rustc_middle::ty::Ty;
1211
use rustc_span::{sym, Symbol};
@@ -18,10 +17,10 @@ use rustc_span::{sym, Symbol};
1817
/// `vec![1,2].drain(..).collect::<HashSet<_>>()`
1918
/// ^^^^^^^^^ ^^^^^^^^^^ false
2019
fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>, sym: Symbol) -> bool {
21-
if let Some(expr_adt_did) = expr.ty_adt_id()
22-
&& let Some(recv_adt_did) = recv.ty_adt_id()
20+
if let Some(expr_adt) = expr.ty_adt_def()
21+
&& let Some(recv_adt) = recv.ty_adt_def()
2322
{
24-
cx.tcx.is_diagnostic_item(sym, expr_adt_did) && cx.tcx.is_diagnostic_item(sym, recv_adt_did)
23+
cx.tcx.is_diagnostic_item(sym, expr_adt.did()) && cx.tcx.is_diagnostic_item(sym, recv_adt.did())
2524
} else {
2625
false
2726
}

clippy_lints/src/methods/redundant_as_str.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use clippy_utils::source::snippet_with_applicability;
44
use rustc_errors::Applicability;
55
use rustc_hir::Expr;
66
use rustc_lint::LateContext;
7-
use rustc_middle::query::Key;
87
use rustc_span::Span;
98

109
pub(super) fn check(
@@ -14,11 +13,7 @@ pub(super) fn check(
1413
as_str_span: Span,
1514
other_method_span: Span,
1615
) {
17-
if cx
18-
.tcx
19-
.lang_items()
20-
.string()
21-
.is_some_and(|id| Some(id) == cx.typeck_results().expr_ty(recv).ty_adt_id())
16+
if cx.typeck_results().expr_ty(recv).ty_adt_def().is_some_and(|adt| Some(adt.did()) == cx.tcx.lang_items().string())
2217
{
2318
let mut applicability = Applicability::MachineApplicable;
2419
span_lint_and_sugg(

clippy_lints/src/mut_key.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use clippy_utils::{def_path_def_ids, trait_ref_of_method};
44
use rustc_data_structures::fx::FxHashSet;
55
use rustc_hir as hir;
66
use rustc_lint::{LateContext, LateLintPass};
7-
use rustc_middle::query::Key;
87
use rustc_middle::ty::{Adt, Ty};
98
use rustc_session::impl_lint_pass;
109
use rustc_span::def_id::LocalDefId;
@@ -166,7 +165,7 @@ impl MutableKeyType {
166165
// Determines if a type contains interior mutability which would affect its implementation of
167166
// [`Hash`] or [`Ord`].
168167
if is_interior_mut_ty(cx, subst_ty)
169-
&& !matches!(subst_ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id))
168+
&& !matches!(subst_ty.ty_adt_def(), Some(adt) if self.ignore_mut_def_ids.contains(&adt.did()))
170169
{
171170
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
172171
}

clippy_lints/src/non_copy_const.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use rustc_hir::{
1515
};
1616
use rustc_lint::{LateContext, LateLintPass, Lint};
1717
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId};
18-
use rustc_middle::query::Key;
1918
use rustc_middle::ty::adjustment::Adjust;
2019
use rustc_middle::ty::{self, Ty, TyCtxt};
2120
use rustc_session::impl_lint_pass;
@@ -188,7 +187,7 @@ impl NonCopyConst {
188187
}
189188

190189
fn is_ty_ignored(&self, ty: Ty<'_>) -> bool {
191-
matches!(ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id))
190+
matches!(ty.ty_adt_def(), Some(adt) if self.ignore_mut_def_ids.contains(&adt.did()))
192191
}
193192

194193
fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {

clippy_lints/src/transmute/transmute_int_to_non_zero.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use clippy_utils::sugg;
44
use rustc_errors::Applicability;
55
use rustc_hir::Expr;
66
use rustc_lint::LateContext;
7-
use rustc_middle::query::Key;
87
use rustc_middle::ty::{self, Ty};
98
use rustc_span::symbol::sym;
109

@@ -17,10 +16,10 @@ pub(super) fn check<'tcx>(
1716
to_ty: Ty<'tcx>,
1817
arg: &'tcx Expr<'_>,
1918
) -> bool {
20-
let (ty::Int(_) | ty::Uint(_), Some(to_ty_id)) = (&from_ty.kind(), to_ty.ty_adt_id()) else {
19+
let (ty::Int(_) | ty::Uint(_), Some(to_ty_adt)) = (&from_ty.kind(), to_ty.ty_adt_def()) else {
2120
return false;
2221
};
23-
let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_id) else {
22+
let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_adt.did()) else {
2423
return false;
2524
};
2625

0 commit comments

Comments
 (0)