Auto merge of #127097 - compiler-errors:async-closure-lint, r=oli-obk
Implement simple, unstable lint to suggest turning closure-of-async-block into async-closure We want to eventually suggest people to turn `|| async {}` to `async || {}`. This begins doing that. It's a pretty rudimentary lint, but I wanted to get something down so I wouldn't lose the code. Tracking: * #62290
This commit is contained in:
commit
9b0043095a
10 changed files with 242 additions and 20 deletions
|
@ -185,6 +185,10 @@ lint_cfg_attr_no_attributes =
|
||||||
|
|
||||||
lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
|
lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
|
||||||
|
|
||||||
|
lint_closure_returning_async_block = closure returning async block can be made into an async closure
|
||||||
|
.label = this async block can be removed, and the closure can be turned into an async closure
|
||||||
|
.suggestion = turn this into an async closure
|
||||||
|
|
||||||
lint_command_line_source = `forbid` lint level was set on command line
|
lint_command_line_source = `forbid` lint level was set on command line
|
||||||
|
|
||||||
lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as identifiers, which look alike
|
lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as identifiers, which look alike
|
||||||
|
|
129
compiler/rustc_lint/src/async_closures.rs
Normal file
129
compiler/rustc_lint/src/async_closures.rs
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_macros::{LintDiagnostic, Subdiagnostic};
|
||||||
|
use rustc_session::{declare_lint, declare_lint_pass};
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
use crate::{LateContext, LateLintPass};
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `closure_returning_async_block` lint detects cases where users
|
||||||
|
/// write a closure that returns an async block.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #![warn(closure_returning_async_block)]
|
||||||
|
/// let c = |x: &str| async {};
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Using an async closure is preferable over a closure that returns an
|
||||||
|
/// async block, since async closures are less restrictive in how its
|
||||||
|
/// captures are allowed to be used.
|
||||||
|
///
|
||||||
|
/// For example, this code does not work with a closure returning an async
|
||||||
|
/// block:
|
||||||
|
///
|
||||||
|
/// ```rust,compile_fail
|
||||||
|
/// async fn callback(x: &str) {}
|
||||||
|
///
|
||||||
|
/// let captured_str = String::new();
|
||||||
|
/// let c = move || async {
|
||||||
|
/// callback(&captured_str).await;
|
||||||
|
/// };
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// But it does work with async closures:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #![feature(async_closure)]
|
||||||
|
///
|
||||||
|
/// async fn callback(x: &str) {}
|
||||||
|
///
|
||||||
|
/// let captured_str = String::new();
|
||||||
|
/// let c = async move || {
|
||||||
|
/// callback(&captured_str).await;
|
||||||
|
/// };
|
||||||
|
/// ```
|
||||||
|
pub CLOSURE_RETURNING_ASYNC_BLOCK,
|
||||||
|
Allow,
|
||||||
|
"closure that returns `async {}` could be rewritten as an async closure",
|
||||||
|
@feature_gate = async_closure;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(
|
||||||
|
/// Lint for potential usages of async closures and async fn trait bounds.
|
||||||
|
AsyncClosureUsage => [CLOSURE_RETURNING_ASYNC_BLOCK]
|
||||||
|
);
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for AsyncClosureUsage {
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||||
|
let hir::ExprKind::Closure(&hir::Closure {
|
||||||
|
body,
|
||||||
|
kind: hir::ClosureKind::Closure,
|
||||||
|
fn_decl_span,
|
||||||
|
..
|
||||||
|
}) = expr.kind
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut body = cx.tcx.hir().body(body).value;
|
||||||
|
|
||||||
|
// Only peel blocks that have no expressions.
|
||||||
|
while let hir::ExprKind::Block(&hir::Block { stmts: [], expr: Some(tail), .. }, None) =
|
||||||
|
body.kind
|
||||||
|
{
|
||||||
|
body = tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hir::ExprKind::Closure(&hir::Closure {
|
||||||
|
kind:
|
||||||
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
|
hir::CoroutineDesugaring::Async,
|
||||||
|
hir::CoroutineSource::Block,
|
||||||
|
)),
|
||||||
|
fn_decl_span: async_decl_span,
|
||||||
|
..
|
||||||
|
}) = body.kind
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let deletion_span = cx.tcx.sess.source_map().span_extend_while_whitespace(async_decl_span);
|
||||||
|
|
||||||
|
cx.tcx.emit_node_span_lint(
|
||||||
|
CLOSURE_RETURNING_ASYNC_BLOCK,
|
||||||
|
expr.hir_id,
|
||||||
|
fn_decl_span,
|
||||||
|
ClosureReturningAsyncBlock {
|
||||||
|
async_decl_span,
|
||||||
|
sugg: AsyncClosureSugg {
|
||||||
|
deletion_span,
|
||||||
|
insertion_span: fn_decl_span.shrink_to_lo(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(lint_closure_returning_async_block)]
|
||||||
|
struct ClosureReturningAsyncBlock {
|
||||||
|
#[label]
|
||||||
|
async_decl_span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
sugg: AsyncClosureSugg,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(lint_suggestion, applicability = "maybe-incorrect")]
|
||||||
|
struct AsyncClosureSugg {
|
||||||
|
#[suggestion_part(code = "")]
|
||||||
|
deletion_span: Span,
|
||||||
|
#[suggestion_part(code = "async ")]
|
||||||
|
insertion_span: Span,
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ use rustc_middle::ty::{
|
||||||
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||||
};
|
};
|
||||||
use rustc_session::{declare_lint, declare_lint_pass};
|
use rustc_session::{declare_lint, declare_lint_pass};
|
||||||
use rustc_span::{sym, Span};
|
use rustc_span::Span;
|
||||||
|
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
use crate::{LateContext, LateLintPass};
|
use crate::{LateContext, LateLintPass};
|
||||||
|
@ -57,7 +57,7 @@ declare_lint! {
|
||||||
pub IMPL_TRAIT_OVERCAPTURES,
|
pub IMPL_TRAIT_OVERCAPTURES,
|
||||||
Allow,
|
Allow,
|
||||||
"`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
|
"`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
|
||||||
@feature_gate = sym::precise_capturing;
|
@feature_gate = precise_capturing;
|
||||||
//@future_incompatible = FutureIncompatibleInfo {
|
//@future_incompatible = FutureIncompatibleInfo {
|
||||||
// reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
|
// reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
|
||||||
// reference: "<FIXME>",
|
// reference: "<FIXME>",
|
||||||
|
@ -91,7 +91,7 @@ declare_lint! {
|
||||||
pub IMPL_TRAIT_REDUNDANT_CAPTURES,
|
pub IMPL_TRAIT_REDUNDANT_CAPTURES,
|
||||||
Warn,
|
Warn,
|
||||||
"redundant precise-capturing `use<...>` syntax on an `impl Trait`",
|
"redundant precise-capturing `use<...>` syntax on an `impl Trait`",
|
||||||
@feature_gate = sym::precise_capturing;
|
@feature_gate = precise_capturing;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint_pass!(
|
declare_lint_pass!(
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#![feature(trait_upcasting)]
|
#![feature(trait_upcasting)]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
|
mod async_closures;
|
||||||
mod async_fn_in_trait;
|
mod async_fn_in_trait;
|
||||||
pub mod builtin;
|
pub mod builtin;
|
||||||
mod context;
|
mod context;
|
||||||
|
@ -87,6 +88,7 @@ use rustc_hir::def_id::LocalModDefId;
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
|
|
||||||
|
use async_closures::AsyncClosureUsage;
|
||||||
use async_fn_in_trait::AsyncFnInTrait;
|
use async_fn_in_trait::AsyncFnInTrait;
|
||||||
use builtin::*;
|
use builtin::*;
|
||||||
use deref_into_dyn_supertrait::*;
|
use deref_into_dyn_supertrait::*;
|
||||||
|
@ -229,6 +231,7 @@ late_lint_methods!(
|
||||||
MapUnitFn: MapUnitFn,
|
MapUnitFn: MapUnitFn,
|
||||||
MissingDebugImplementations: MissingDebugImplementations,
|
MissingDebugImplementations: MissingDebugImplementations,
|
||||||
MissingDoc: MissingDoc,
|
MissingDoc: MissingDoc,
|
||||||
|
AsyncClosureUsage: AsyncClosureUsage,
|
||||||
AsyncFnInTrait: AsyncFnInTrait,
|
AsyncFnInTrait: AsyncFnInTrait,
|
||||||
NonLocalDefinitions: NonLocalDefinitions::default(),
|
NonLocalDefinitions: NonLocalDefinitions::default(),
|
||||||
ImplTraitOvercaptures: ImplTraitOvercaptures,
|
ImplTraitOvercaptures: ImplTraitOvercaptures,
|
||||||
|
|
|
@ -2,7 +2,6 @@ use crate::{LateContext, LateLintPass, LintContext};
|
||||||
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_session::{declare_lint, declare_lint_pass};
|
use rustc_session::{declare_lint, declare_lint_pass};
|
||||||
use rustc_span::sym;
|
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple
|
/// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple
|
||||||
|
@ -30,7 +29,7 @@ declare_lint! {
|
||||||
pub MULTIPLE_SUPERTRAIT_UPCASTABLE,
|
pub MULTIPLE_SUPERTRAIT_UPCASTABLE,
|
||||||
Allow,
|
Allow,
|
||||||
"detect when an object-safe trait has multiple supertraits",
|
"detect when an object-safe trait has multiple supertraits",
|
||||||
@feature_gate = sym::multiple_supertrait_upcastable;
|
@feature_gate = multiple_supertrait_upcastable;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]);
|
declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]);
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason};
|
use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::symbol::sym;
|
|
||||||
|
|
||||||
declare_lint_pass! {
|
declare_lint_pass! {
|
||||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||||
|
@ -463,7 +462,7 @@ declare_lint! {
|
||||||
pub MUST_NOT_SUSPEND,
|
pub MUST_NOT_SUSPEND,
|
||||||
Allow,
|
Allow,
|
||||||
"use of a `#[must_not_suspend]` value across a yield point",
|
"use of a `#[must_not_suspend]` value across a yield point",
|
||||||
@feature_gate = rustc_span::symbol::sym::must_not_suspend;
|
@feature_gate = must_not_suspend;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
@ -1647,7 +1646,7 @@ declare_lint! {
|
||||||
pub RUST_2024_INCOMPATIBLE_PAT,
|
pub RUST_2024_INCOMPATIBLE_PAT,
|
||||||
Allow,
|
Allow,
|
||||||
"detects patterns whose meaning will change in Rust 2024",
|
"detects patterns whose meaning will change in Rust 2024",
|
||||||
@feature_gate = sym::ref_pat_eat_one_layer_2024;
|
@feature_gate = ref_pat_eat_one_layer_2024;
|
||||||
// FIXME uncomment below upon stabilization
|
// FIXME uncomment below upon stabilization
|
||||||
/*@future_incompatible = FutureIncompatibleInfo {
|
/*@future_incompatible = FutureIncompatibleInfo {
|
||||||
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
|
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
|
||||||
|
@ -2695,7 +2694,7 @@ declare_lint! {
|
||||||
pub FUZZY_PROVENANCE_CASTS,
|
pub FUZZY_PROVENANCE_CASTS,
|
||||||
Allow,
|
Allow,
|
||||||
"a fuzzy integer to pointer cast is used",
|
"a fuzzy integer to pointer cast is used",
|
||||||
@feature_gate = sym::strict_provenance;
|
@feature_gate = strict_provenance;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
@ -2741,7 +2740,7 @@ declare_lint! {
|
||||||
pub LOSSY_PROVENANCE_CASTS,
|
pub LOSSY_PROVENANCE_CASTS,
|
||||||
Allow,
|
Allow,
|
||||||
"a lossy pointer to integer cast is used",
|
"a lossy pointer to integer cast is used",
|
||||||
@feature_gate = sym::strict_provenance;
|
@feature_gate = strict_provenance;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
@ -3925,7 +3924,7 @@ declare_lint! {
|
||||||
pub NON_EXHAUSTIVE_OMITTED_PATTERNS,
|
pub NON_EXHAUSTIVE_OMITTED_PATTERNS,
|
||||||
Allow,
|
Allow,
|
||||||
"detect when patterns of types marked `non_exhaustive` are missed",
|
"detect when patterns of types marked `non_exhaustive` are missed",
|
||||||
@feature_gate = sym::non_exhaustive_omitted_patterns_lint;
|
@feature_gate = non_exhaustive_omitted_patterns_lint;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
@ -4045,7 +4044,7 @@ declare_lint! {
|
||||||
pub TEST_UNSTABLE_LINT,
|
pub TEST_UNSTABLE_LINT,
|
||||||
Deny,
|
Deny,
|
||||||
"this unstable lint is only for testing",
|
"this unstable lint is only for testing",
|
||||||
@feature_gate = sym::test_unstable_lint;
|
@feature_gate = test_unstable_lint;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
|
|
@ -865,7 +865,7 @@ macro_rules! declare_lint {
|
||||||
);
|
);
|
||||||
);
|
);
|
||||||
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
|
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
|
||||||
$(@feature_gate = $gate:expr;)?
|
$(@feature_gate = $gate:ident;)?
|
||||||
$(@future_incompatible = FutureIncompatibleInfo {
|
$(@future_incompatible = FutureIncompatibleInfo {
|
||||||
reason: $reason:expr,
|
reason: $reason:expr,
|
||||||
$($field:ident : $val:expr),* $(,)*
|
$($field:ident : $val:expr),* $(,)*
|
||||||
|
@ -879,7 +879,7 @@ macro_rules! declare_lint {
|
||||||
desc: $desc,
|
desc: $desc,
|
||||||
is_externally_loaded: false,
|
is_externally_loaded: false,
|
||||||
$($v: true,)*
|
$($v: true,)*
|
||||||
$(feature_gate: Some($gate),)?
|
$(feature_gate: Some(rustc_span::symbol::sym::$gate),)?
|
||||||
$(future_incompatible: Some($crate::FutureIncompatibleInfo {
|
$(future_incompatible: Some($crate::FutureIncompatibleInfo {
|
||||||
reason: $reason,
|
reason: $reason,
|
||||||
$($field: $val,)*
|
$($field: $val,)*
|
||||||
|
@ -895,21 +895,21 @@ macro_rules! declare_lint {
|
||||||
macro_rules! declare_tool_lint {
|
macro_rules! declare_tool_lint {
|
||||||
(
|
(
|
||||||
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
|
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
|
||||||
$(, @feature_gate = $gate:expr;)?
|
$(, @feature_gate = $gate:ident;)?
|
||||||
) => (
|
) => (
|
||||||
$crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @feature_gate = $gate;)?}
|
$crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @feature_gate = $gate;)?}
|
||||||
);
|
);
|
||||||
(
|
(
|
||||||
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
|
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
|
||||||
report_in_external_macro: $rep:expr
|
report_in_external_macro: $rep:expr
|
||||||
$(, @feature_gate = $gate:expr;)?
|
$(, @feature_gate = $gate:ident;)?
|
||||||
) => (
|
) => (
|
||||||
$crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?}
|
$crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?}
|
||||||
);
|
);
|
||||||
(
|
(
|
||||||
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
|
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
|
||||||
$external:expr
|
$external:expr
|
||||||
$(, @feature_gate = $gate:expr;)?
|
$(, @feature_gate = $gate:ident;)?
|
||||||
) => (
|
) => (
|
||||||
$(#[$attr])*
|
$(#[$attr])*
|
||||||
$vis static $NAME: &$crate::Lint = &$crate::Lint {
|
$vis static $NAME: &$crate::Lint = &$crate::Lint {
|
||||||
|
@ -920,7 +920,7 @@ macro_rules! declare_tool_lint {
|
||||||
report_in_external_macro: $external,
|
report_in_external_macro: $external,
|
||||||
future_incompatible: None,
|
future_incompatible: None,
|
||||||
is_externally_loaded: true,
|
is_externally_loaded: true,
|
||||||
$(feature_gate: Some($gate),)?
|
$(feature_gate: Some(rustc_span::symbol::sym::$gate),)?
|
||||||
crate_level_only: false,
|
crate_level_only: false,
|
||||||
..$crate::Lint::default_fields_for_macro()
|
..$crate::Lint::default_fields_for_macro()
|
||||||
};
|
};
|
||||||
|
|
|
@ -66,7 +66,7 @@ where
|
||||||
macro_rules! declare_rustdoc_lint {
|
macro_rules! declare_rustdoc_lint {
|
||||||
(
|
(
|
||||||
$(#[$attr:meta])* $name: ident, $level: ident, $descr: literal $(,)?
|
$(#[$attr:meta])* $name: ident, $level: ident, $descr: literal $(,)?
|
||||||
$(@feature_gate = $gate:expr;)?
|
$(@feature_gate = $gate:ident;)?
|
||||||
) => {
|
) => {
|
||||||
declare_tool_lint! {
|
declare_tool_lint! {
|
||||||
$(#[$attr])* pub rustdoc::$name, $level, $descr
|
$(#[$attr])* pub rustdoc::$name, $level, $descr
|
||||||
|
@ -128,7 +128,7 @@ declare_rustdoc_lint! {
|
||||||
MISSING_DOC_CODE_EXAMPLES,
|
MISSING_DOC_CODE_EXAMPLES,
|
||||||
Allow,
|
Allow,
|
||||||
"detects publicly-exported items without code samples in their documentation",
|
"detects publicly-exported items without code samples in their documentation",
|
||||||
@feature_gate = rustc_span::symbol::sym::rustdoc_missing_doc_code_examples;
|
@feature_gate = rustdoc_missing_doc_code_examples;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_rustdoc_lint! {
|
declare_rustdoc_lint! {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
//@ edition: 2021
|
||||||
|
|
||||||
|
#![feature(async_closure)]
|
||||||
|
#![deny(closure_returning_async_block)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = || async {};
|
||||||
|
//~^ ERROR closure returning async block can be made into an async closure
|
||||||
|
|
||||||
|
let x = || async move {};
|
||||||
|
//~^ ERROR closure returning async block can be made into an async closure
|
||||||
|
|
||||||
|
let x = move || async move {};
|
||||||
|
//~^ ERROR closure returning async block can be made into an async closure
|
||||||
|
|
||||||
|
let x = move || async {};
|
||||||
|
//~^ ERROR closure returning async block can be made into an async closure
|
||||||
|
|
||||||
|
let x = || {{ async {} }};
|
||||||
|
//~^ ERROR closure returning async block can be made into an async closure
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
error: closure returning async block can be made into an async closure
|
||||||
|
--> $DIR/lint-closure-returning-async-block.rs:7:13
|
||||||
|
|
|
||||||
|
LL | let x = || async {};
|
||||||
|
| ^^ ----- this async block can be removed, and the closure can be turned into an async closure
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/lint-closure-returning-async-block.rs:4:9
|
||||||
|
|
|
||||||
|
LL | #![deny(closure_returning_async_block)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
help: turn this into an async closure
|
||||||
|
|
|
||||||
|
LL - let x = || async {};
|
||||||
|
LL + let x = async || {};
|
||||||
|
|
|
||||||
|
|
||||||
|
error: closure returning async block can be made into an async closure
|
||||||
|
--> $DIR/lint-closure-returning-async-block.rs:10:13
|
||||||
|
|
|
||||||
|
LL | let x = || async move {};
|
||||||
|
| ^^ ---------- this async block can be removed, and the closure can be turned into an async closure
|
||||||
|
|
|
||||||
|
help: turn this into an async closure
|
||||||
|
|
|
||||||
|
LL - let x = || async move {};
|
||||||
|
LL + let x = async || {};
|
||||||
|
|
|
||||||
|
|
||||||
|
error: closure returning async block can be made into an async closure
|
||||||
|
--> $DIR/lint-closure-returning-async-block.rs:13:13
|
||||||
|
|
|
||||||
|
LL | let x = move || async move {};
|
||||||
|
| ^^^^^^^ ---------- this async block can be removed, and the closure can be turned into an async closure
|
||||||
|
|
|
||||||
|
help: turn this into an async closure
|
||||||
|
|
|
||||||
|
LL - let x = move || async move {};
|
||||||
|
LL + let x = async move || {};
|
||||||
|
|
|
||||||
|
|
||||||
|
error: closure returning async block can be made into an async closure
|
||||||
|
--> $DIR/lint-closure-returning-async-block.rs:16:13
|
||||||
|
|
|
||||||
|
LL | let x = move || async {};
|
||||||
|
| ^^^^^^^ ----- this async block can be removed, and the closure can be turned into an async closure
|
||||||
|
|
|
||||||
|
help: turn this into an async closure
|
||||||
|
|
|
||||||
|
LL - let x = move || async {};
|
||||||
|
LL + let x = async move || {};
|
||||||
|
|
|
||||||
|
|
||||||
|
error: closure returning async block can be made into an async closure
|
||||||
|
--> $DIR/lint-closure-returning-async-block.rs:19:13
|
||||||
|
|
|
||||||
|
LL | let x = || {{ async {} }};
|
||||||
|
| ^^ ----- this async block can be removed, and the closure can be turned into an async closure
|
||||||
|
|
|
||||||
|
help: turn this into an async closure
|
||||||
|
|
|
||||||
|
LL - let x = || {{ async {} }};
|
||||||
|
LL + let x = async || {{ {} }};
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue