Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b781645

Browse files
committedOct 5, 2023
Auto merge of #116184 - compiler-errors:afit-lint, r=tmandry
Add `async_fn_in_trait` lint cc #115822 (comment) Mostly unsure what the messaging should be. Feedback required. r? `@tmandry`
2 parents afe67fa + 2f52490 commit b781645

33 files changed

+308
-60
lines changed
 

‎compiler/rustc_lint/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ lint_array_into_iter =
55
.use_explicit_into_iter_suggestion =
66
or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
77
8+
lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified
9+
.note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`
10+
.suggestion = you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`
11+
812
lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering
913
.help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`
1014
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
use crate::lints::AsyncFnInTraitDiag;
2+
use crate::LateContext;
3+
use crate::LateLintPass;
4+
use rustc_hir as hir;
5+
use rustc_trait_selection::traits::error_reporting::suggestions::suggest_desugaring_async_fn_to_impl_future_in_trait;
6+
7+
declare_lint! {
8+
/// The `async_fn_in_trait` lint detects use of `async fn` in the
9+
/// definition of a publicly-reachable trait.
10+
///
11+
/// ### Example
12+
///
13+
/// ```rust
14+
/// # #![feature(async_fn_in_trait)]
15+
/// pub trait Trait {
16+
/// async fn method(&self);
17+
/// }
18+
/// # fn main() {}
19+
/// ```
20+
///
21+
/// {{produces}}
22+
///
23+
/// ### Explanation
24+
///
25+
/// When `async fn` is used in a trait definition, the trait does not
26+
/// promise that the opaque [`Future`] returned by the associated function
27+
/// or method will implement any [auto traits] such as [`Send`]. This may
28+
/// be surprising and may make the associated functions or methods on the
29+
/// trait less useful than intended. On traits exposed publicly from a
30+
/// crate, this may affect downstream crates whose authors cannot alter
31+
/// the trait definition.
32+
///
33+
/// For example, this code is invalid:
34+
///
35+
/// ```rust,compile_fail
36+
/// # #![feature(async_fn_in_trait)]
37+
/// pub trait Trait {
38+
/// async fn method(&self) {}
39+
/// }
40+
///
41+
/// fn test<T: Trait>(x: T) {
42+
/// fn spawn<T: Send>(_: T) {}
43+
/// spawn(x.method()); // Not OK.
44+
/// }
45+
/// ```
46+
///
47+
/// This lint exists to warn authors of publicly-reachable traits that
48+
/// they may want to consider desugaring the `async fn` to a normal `fn`
49+
/// that returns an opaque `impl Future<..> + Send` type.
50+
///
51+
/// For example, instead of:
52+
///
53+
/// ```rust
54+
/// # #![feature(async_fn_in_trait)]
55+
/// pub trait Trait {
56+
/// async fn method(&self) {}
57+
/// }
58+
/// ```
59+
///
60+
/// The author of the trait may want to write:
61+
///
62+
///
63+
/// ```rust
64+
/// # #![feature(return_position_impl_trait_in_trait)]
65+
/// use core::future::Future;
66+
/// pub trait Trait {
67+
/// fn method(&self) -> impl Future<Output = ()> + Send { async {} }
68+
/// }
69+
/// ```
70+
///
71+
/// This still allows the use of `async fn` within impls of the trait.
72+
/// However, it also means that the trait will never be compatible with
73+
/// impls where the returned [`Future`] of the method does not implement
74+
/// `Send`.
75+
///
76+
/// Conversely, if the trait is used only locally, if it is never used in
77+
/// generic functions, or if it is only used in single-threaded contexts
78+
/// that do not care whether the returned [`Future`] implements [`Send`],
79+
/// then the lint may be suppressed.
80+
///
81+
/// [`Future`]: https://doc.rust-lang.org/core/future/trait.Future.html
82+
/// [`Send`]: https://doc.rust-lang.org/core/marker/trait.Send.html
83+
/// [auto traits]: https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits
84+
pub ASYNC_FN_IN_TRAIT,
85+
Warn,
86+
"use of `async fn` in definition of a publicly-reachable trait"
87+
}
88+
89+
declare_lint_pass!(
90+
/// Lint for use of `async fn` in the definition of a publicly-reachable
91+
/// trait.
92+
AsyncFnInTrait => [ASYNC_FN_IN_TRAIT]
93+
);
94+
95+
impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait {
96+
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'tcx>) {
97+
if let hir::TraitItemKind::Fn(sig, body) = item.kind
98+
&& let hir::IsAsync::Async(async_span) = sig.header.asyncness
99+
{
100+
// RTN can be used to bound `async fn` in traits in a better way than "always"
101+
if cx.tcx.features().return_type_notation {
102+
return;
103+
}
104+
105+
// Only need to think about library implications of reachable traits
106+
if !cx.tcx.effective_visibilities(()).is_reachable(item.owner_id.def_id) {
107+
return;
108+
}
109+
110+
let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) =
111+
sig.decl.output
112+
else {
113+
// This should never happen, but let's not ICE.
114+
return;
115+
};
116+
let sugg = suggest_desugaring_async_fn_to_impl_future_in_trait(
117+
cx.tcx,
118+
sig,
119+
body,
120+
def.owner_id.def_id,
121+
" + Send",
122+
);
123+
cx.tcx.emit_spanned_lint(ASYNC_FN_IN_TRAIT, item.hir_id(), async_span, AsyncFnInTraitDiag {
124+
sugg
125+
});
126+
}
127+
}
128+
}

‎compiler/rustc_lint/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ extern crate rustc_session;
5050
extern crate tracing;
5151

5252
mod array_into_iter;
53+
mod async_fn_in_trait;
5354
pub mod builtin;
5455
mod context;
5556
mod deref_into_dyn_supertrait;
@@ -96,6 +97,7 @@ use rustc_session::lint::builtin::{
9697
};
9798

9899
use array_into_iter::ArrayIntoIter;
100+
use async_fn_in_trait::AsyncFnInTrait;
99101
use builtin::*;
100102
use deref_into_dyn_supertrait::*;
101103
use drop_forget_useless::*;
@@ -234,6 +236,7 @@ late_lint_methods!(
234236
MapUnitFn: MapUnitFn,
235237
MissingDebugImplementations: MissingDebugImplementations,
236238
MissingDoc: MissingDoc,
239+
AsyncFnInTrait: AsyncFnInTrait,
237240
]
238241
]
239242
);

‎compiler/rustc_lint/src/lints.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,3 +1818,24 @@ pub struct UnusedAllocationDiag;
18181818
#[derive(LintDiagnostic)]
18191819
#[diag(lint_unused_allocation_mut)]
18201820
pub struct UnusedAllocationMutDiag;
1821+
1822+
pub struct AsyncFnInTraitDiag {
1823+
pub sugg: Option<Vec<(Span, String)>>,
1824+
}
1825+
1826+
impl<'a> DecorateLint<'a, ()> for AsyncFnInTraitDiag {
1827+
fn decorate_lint<'b>(
1828+
self,
1829+
diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
1830+
) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
1831+
diag.note(fluent::lint_note);
1832+
if let Some(sugg) = self.sugg {
1833+
diag.multipart_suggestion(fluent::lint_suggestion, sugg, Applicability::MaybeIncorrect);
1834+
}
1835+
diag
1836+
}
1837+
1838+
fn msg(&self) -> rustc_errors::DiagnosticMessage {
1839+
fluent::lint_async_fn_in_trait
1840+
}
1841+
}

‎compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Lines changed: 69 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4000,14 +4000,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
40004000

40014001
// ... whose signature is `async` (i.e. this is an AFIT)
40024002
let (sig, body) = item.expect_fn();
4003-
let hir::IsAsync::Async(async_span) = sig.header.asyncness else {
4004-
return;
4005-
};
4006-
let Ok(async_span) =
4007-
self.tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace())
4008-
else {
4009-
return;
4010-
};
40114003
let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) =
40124004
sig.decl.output
40134005
else {
@@ -4021,55 +4013,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
40214013
return;
40224014
}
40234015

4024-
let future = self.tcx.hir().item(*def).expect_opaque_ty();
4025-
let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else {
4026-
// `async fn` should always lower to a lang item bound... but don't ICE.
4027-
return;
4028-
};
4029-
let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) =
4030-
generics.bindings.get(0).map(|binding| binding.kind)
4031-
else {
4032-
// Also should never happen.
4016+
let Some(sugg) = suggest_desugaring_async_fn_to_impl_future_in_trait(
4017+
self.tcx,
4018+
*sig,
4019+
*body,
4020+
opaque_def_id.expect_local(),
4021+
&format!(" + {auto_trait}"),
4022+
) else {
40334023
return;
40344024
};
40354025

40364026
let function_name = self.tcx.def_path_str(fn_def_id);
4037-
4038-
let mut sugg = if future_output_ty.span.is_empty() {
4039-
vec![
4040-
(async_span, String::new()),
4041-
(
4042-
future_output_ty.span,
4043-
format!(" -> impl std::future::Future<Output = ()> + {auto_trait}"),
4044-
),
4045-
]
4046-
} else {
4047-
vec![
4048-
(
4049-
future_output_ty.span.shrink_to_lo(),
4050-
"impl std::future::Future<Output = ".to_owned(),
4051-
),
4052-
(future_output_ty.span.shrink_to_hi(), format!("> + {auto_trait}")),
4053-
(async_span, String::new()),
4054-
]
4055-
};
4056-
4057-
// If there's a body, we also need to wrap it in `async {}`
4058-
if let hir::TraitFn::Provided(body) = body {
4059-
let body = self.tcx.hir().body(*body);
4060-
let body_span = body.value.span;
4061-
let body_span_without_braces =
4062-
body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1));
4063-
if body_span_without_braces.is_empty() {
4064-
sugg.push((body_span_without_braces, " async {} ".to_owned()));
4065-
} else {
4066-
sugg.extend([
4067-
(body_span_without_braces.shrink_to_lo(), "async {".to_owned()),
4068-
(body_span_without_braces.shrink_to_hi(), "} ".to_owned()),
4069-
]);
4070-
}
4071-
}
4072-
40734027
err.multipart_suggestion(
40744028
format!(
40754029
"`{auto_trait}` can be made part of the associated future's \
@@ -4321,3 +4275,65 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceImplTraitFolder<'tcx> {
43214275
self.tcx
43224276
}
43234277
}
4278+
4279+
pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
4280+
tcx: TyCtxt<'tcx>,
4281+
sig: hir::FnSig<'tcx>,
4282+
body: hir::TraitFn<'tcx>,
4283+
opaque_def_id: LocalDefId,
4284+
add_bounds: &str,
4285+
) -> Option<Vec<(Span, String)>> {
4286+
let hir::IsAsync::Async(async_span) = sig.header.asyncness else {
4287+
return None;
4288+
};
4289+
let Ok(async_span) = tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace())
4290+
else {
4291+
return None;
4292+
};
4293+
4294+
let future = tcx.hir().get_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
4295+
let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else {
4296+
// `async fn` should always lower to a lang item bound... but don't ICE.
4297+
return None;
4298+
};
4299+
let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) =
4300+
generics.bindings.get(0).map(|binding| binding.kind)
4301+
else {
4302+
// Also should never happen.
4303+
return None;
4304+
};
4305+
4306+
let mut sugg = if future_output_ty.span.is_empty() {
4307+
vec![
4308+
(async_span, String::new()),
4309+
(
4310+
future_output_ty.span,
4311+
format!(" -> impl std::future::Future<Output = ()>{add_bounds}"),
4312+
),
4313+
]
4314+
} else {
4315+
vec![
4316+
(future_output_ty.span.shrink_to_lo(), "impl std::future::Future<Output = ".to_owned()),
4317+
(future_output_ty.span.shrink_to_hi(), format!(">{add_bounds}")),
4318+
(async_span, String::new()),
4319+
]
4320+
};
4321+
4322+
// If there's a body, we also need to wrap it in `async {}`
4323+
if let hir::TraitFn::Provided(body) = body {
4324+
let body = tcx.hir().body(body);
4325+
let body_span = body.value.span;
4326+
let body_span_without_braces =
4327+
body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1));
4328+
if body_span_without_braces.is_empty() {
4329+
sugg.push((body_span_without_braces, " async {} ".to_owned()));
4330+
} else {
4331+
sugg.extend([
4332+
(body_span_without_braces.shrink_to_lo(), "async {".to_owned()),
4333+
(body_span_without_braces.shrink_to_hi(), "} ".to_owned()),
4334+
]);
4335+
}
4336+
}
4337+
4338+
Some(sugg)
4339+
}

‎tests/ui/async-await/in-trait/async-associated-types.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ use std::fmt::Debug;
99
trait MyTrait<'a, 'b, T> where Self: 'a, T: Debug + Sized + 'b {
1010
type MyAssoc;
1111

12+
#[allow(async_fn_in_trait)]
1213
async fn foo(&'a self, key: &'b T) -> Self::MyAssoc;
1314
}
1415

1516
impl<'a, 'b, T: Debug + Sized + 'b, U: 'a> MyTrait<'a, 'b, T> for U {
1617
type MyAssoc = (&'a U, &'b T);
1718

19+
#[allow(async_fn_in_trait)]
1820
async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
1921
(self, key)
2022
}

‎tests/ui/async-await/in-trait/async-default-fn-overridden.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
use std::future::Future;
77

88
trait AsyncTrait {
9+
#[allow(async_fn_in_trait)]
910
async fn default_impl() {
1011
assert!(false);
1112
}
1213

14+
#[allow(async_fn_in_trait)]
1315
async fn call_default_impl() {
1416
Self::default_impl().await
1517
}

‎tests/ui/async-await/in-trait/async-example-desugared-extra.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::pin::Pin;
1010
use std::task::Poll;
1111

1212
pub trait MyTrait {
13+
#[allow(async_fn_in_trait)]
1314
async fn foo(&self) -> i32;
1415
}
1516

‎tests/ui/async-await/in-trait/async-example-desugared.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use std::future::Future;
99

1010
trait MyTrait {
11+
#[allow(async_fn_in_trait)]
1112
async fn foo(&self) -> i32;
1213
}
1314

‎tests/ui/async-await/in-trait/async-example.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
#![allow(incomplete_features)]
66

77
trait MyTrait {
8+
#[allow(async_fn_in_trait)]
89
async fn foo(&self) -> i32;
10+
11+
#[allow(async_fn_in_trait)]
912
async fn bar(&self) -> i32;
1013
}
1114

‎tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use std::fmt::Debug;
88

99
trait MyTrait<'a, 'b, T> {
10+
#[allow(async_fn_in_trait)]
1011
async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T) where T: Debug + Sized;
1112
}
1213

‎tests/ui/async-await/in-trait/async-lifetimes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![allow(incomplete_features)]
66

77
trait MyTrait<'a, 'b, T> {
8+
#[allow(async_fn_in_trait)]
89
async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T);
910
}
1011

‎tests/ui/async-await/in-trait/early-bound-1.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![allow(incomplete_features)]
66

77
pub trait Foo {
8+
#[allow(async_fn_in_trait)]
89
async fn foo(&mut self);
910
}
1011

‎tests/ui/async-await/in-trait/early-bound-2.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![allow(incomplete_features)]
66

77
pub trait Foo {
8+
#[allow(async_fn_in_trait)]
89
async fn foo(&mut self);
910
}
1011

‎tests/ui/async-await/in-trait/implied-bounds.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
trait TcpStack {
88
type Connection<'a>: Sized where Self: 'a;
99
fn connect<'a>(&'a self) -> Self::Connection<'a>;
10+
11+
#[allow(async_fn_in_trait)]
1012
async fn async_connect<'a>(&'a self) -> Self::Connection<'a>;
1113
}
1214

‎tests/ui/async-await/in-trait/issue-102138.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ async fn yield_now() {}
1010

1111
trait AsyncIterator {
1212
type Item;
13+
14+
#[allow(async_fn_in_trait)]
1315
async fn next(&mut self) -> Option<Self::Item>;
1416
}
1517

‎tests/ui/async-await/in-trait/issue-102219.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
#![allow(incomplete_features)]
77

88
trait T {
9+
#[allow(async_fn_in_trait)]
910
async fn foo();
1011
}

‎tests/ui/async-await/in-trait/issue-102310.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![allow(incomplete_features)]
66

77
pub trait SpiDevice {
8+
#[allow(async_fn_in_trait)]
89
async fn transaction<F, R>(&mut self);
910
}
1011

‎tests/ui/async-await/in-trait/issue-104678.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::future::Future;
88
pub trait Pool {
99
type Conn;
1010

11+
#[allow(async_fn_in_trait)]
1112
async fn async_callback<'a, F: FnOnce(&'a Self::Conn) -> Fut, Fut: Future<Output = ()>>(
1213
&'a self,
1314
callback: F,

‎tests/ui/async-await/in-trait/nested-rpit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::future::Future;
99
use std::marker::PhantomData;
1010

1111
trait Lockable<K, V> {
12+
#[allow(async_fn_in_trait)]
1213
async fn lock_all_entries(&self) -> impl Future<Output = Guard<'_>>;
1314
}
1415

‎tests/ui/async-await/in-trait/normalize-opaque-with-bound-vars.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
pub struct SharedState {}
1212

1313
pub trait State {
14+
#[allow(async_fn_in_trait)]
1415
async fn execute(self, shared_state: &SharedState);
1516
}
1617

‎tests/ui/async-await/in-trait/warn.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// edition: 2021
2+
3+
#![feature(async_fn_in_trait)]
4+
#![deny(async_fn_in_trait)]
5+
6+
pub trait Foo {
7+
async fn not_send();
8+
//~^ ERROR use of `async fn` in public traits is discouraged
9+
}
10+
11+
mod private {
12+
pub trait FooUnreachable {
13+
async fn not_send();
14+
// No warning
15+
}
16+
}
17+
18+
pub(crate) trait FooCrate {
19+
async fn not_send();
20+
// No warning
21+
}
22+
23+
fn main() {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified
2+
--> $DIR/warn.rs:7:5
3+
|
4+
LL | async fn not_send();
5+
| ^^^^^
6+
|
7+
= note: you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`
8+
note: the lint level is defined here
9+
--> $DIR/warn.rs:4:9
10+
|
11+
LL | #![deny(async_fn_in_trait)]
12+
| ^^^^^^^^^^^^^^^^^
13+
help: you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`
14+
|
15+
LL - async fn not_send();
16+
LL + fn not_send() -> impl std::future::Future<Output = ()> + Send;
17+
|
18+
19+
error: aborting due to previous error
20+

‎tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0658]: return type notation is experimental
2-
--> $DIR/feature-gate-return_type_notation.rs:14:17
2+
--> $DIR/feature-gate-return_type_notation.rs:15:17
33
|
44
LL | fn foo<T: Trait<m(): Send>>() {}
55
| ^^^^^^^^^
@@ -8,15 +8,15 @@ LL | fn foo<T: Trait<m(): Send>>() {}
88
= help: add `#![feature(return_type_notation)]` to the crate attributes to enable
99

1010
error: parenthesized generic arguments cannot be used in associated type constraints
11-
--> $DIR/feature-gate-return_type_notation.rs:14:17
11+
--> $DIR/feature-gate-return_type_notation.rs:15:17
1212
|
1313
LL | fn foo<T: Trait<m(): Send>>() {}
1414
| ^--
1515
| |
1616
| help: remove these parentheses
1717

1818
error[E0220]: associated type `m` not found for `Trait`
19-
--> $DIR/feature-gate-return_type_notation.rs:14:17
19+
--> $DIR/feature-gate-return_type_notation.rs:15:17
2020
|
2121
LL | fn foo<T: Trait<m(): Send>>() {}
2222
| ^ associated type `m` not found

‎tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
warning: return type notation is experimental
2-
--> $DIR/feature-gate-return_type_notation.rs:14:17
2+
--> $DIR/feature-gate-return_type_notation.rs:15:17
33
|
44
LL | fn foo<T: Trait<m(): Send>>() {}
55
| ^^^^^^^^^

‎tests/ui/feature-gates/feature-gate-return_type_notation.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#![feature(async_fn_in_trait)]
88

99
trait Trait {
10+
#[allow(async_fn_in_trait)]
1011
async fn m();
1112
}
1213

‎tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ trait AsyncLendingIterator {
99
where
1010
Self: 'a;
1111

12+
#[allow(async_fn_in_trait)]
1213
async fn next(&mut self) -> Option<Self::Item<'_>>;
1314
}
1415

‎tests/ui/impl-trait/in-trait/default-body-with-rpit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use std::fmt::Debug;
88

99
trait Foo {
10+
#[allow(async_fn_in_trait)]
1011
async fn baz(&self) -> impl Debug {
1112
""
1213
}

‎tests/ui/impl-trait/in-trait/default-body.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use std::fmt::Debug;
88

99
trait Foo {
10+
#[allow(async_fn_in_trait)]
1011
async fn baz(&self) -> &str {
1112
""
1213
}

‎tests/ui/impl-trait/in-trait/early.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![allow(incomplete_features)]
66

77
pub trait Foo {
8+
#[allow(async_fn_in_trait)]
89
async fn bar<'a: 'a>(&'a mut self);
910
}
1011

‎tests/ui/impl-trait/in-trait/suggest-missing-item.fixed

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
55

66
trait Trait {
7+
#[allow(async_fn_in_trait)]
78
async fn foo();
89

10+
#[allow(async_fn_in_trait)]
911
async fn bar() -> i32;
1012

1113
fn test(&self) -> impl Sized + '_;
1214

15+
#[allow(async_fn_in_trait)]
1316
async fn baz(&self) -> &i32;
1417
}
1518

‎tests/ui/impl-trait/in-trait/suggest-missing-item.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
55

66
trait Trait {
7+
#[allow(async_fn_in_trait)]
78
async fn foo();
89

10+
#[allow(async_fn_in_trait)]
911
async fn bar() -> i32;
1012

1113
fn test(&self) -> impl Sized + '_;
1214

15+
#[allow(async_fn_in_trait)]
1316
async fn baz(&self) -> &i32;
1417
}
1518

‎tests/ui/impl-trait/in-trait/suggest-missing-item.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `test`, `baz`
2-
--> $DIR/suggest-missing-item.rs:18:1
2+
--> $DIR/suggest-missing-item.rs:21:1
33
|
44
LL | async fn foo();
55
| --------------- `foo` from trait
6-
LL |
6+
...
77
LL | async fn bar() -> i32;
88
| ---------------------- `bar` from trait
99
LL |
1010
LL | fn test(&self) -> impl Sized + '_;
1111
| ---------------------------------- `test` from trait
12-
LL |
12+
...
1313
LL | async fn baz(&self) -> &i32;
1414
| ---------------------------- `baz` from trait
1515
...

0 commit comments

Comments
 (0)
Please sign in to comment.