Skip to content

Commit b65819f

Browse files
authored
Unrolled build for #148491
Rollup merge of #148491 - estebank:issue-147894, r=jackh726 Correctly provide suggestions when encountering `async fn` with a `dyn Trait` return type Point at return type of `async fn`s instead of their def `Span`. Correctly provide suggestions when encountering `async fn` with a `dyn Trait` return type. Correctly address `type Alias = dyn Trait` when `fn foo() -> Alias { .. }`. Fix #147894.
2 parents bad5026 + f7eaaf7 commit b65819f

30 files changed

+394
-109
lines changed

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,7 +1670,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16701670
let output = match coro {
16711671
Some(coro) => {
16721672
let fn_def_id = self.local_def_id(fn_node_id);
1673-
self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind, fn_span)
1673+
self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind)
16741674
}
16751675
None => match &decl.output {
16761676
FnRetTy::Ty(ty) => {
@@ -1755,9 +1755,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
17551755
fn_def_id: LocalDefId,
17561756
coro: CoroutineKind,
17571757
fn_kind: FnDeclKind,
1758-
fn_span: Span,
17591758
) -> hir::FnRetTy<'hir> {
1760-
let span = self.lower_span(fn_span);
1759+
let span = self.lower_span(output.span());
17611760

17621761
let (opaque_ty_node_id, allowed_features) = match coro {
17631762
CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None),

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

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1886,12 +1886,56 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
18861886
let ty::Dynamic(_, _) = trait_pred.self_ty().skip_binder().kind() else {
18871887
return false;
18881888
};
1889+
if let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. })
1890+
| Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(fn_sig, _), .. })
1891+
| Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(fn_sig, _), .. }) =
1892+
self.tcx.hir_node_by_def_id(obligation.cause.body_id)
1893+
&& let hir::FnRetTy::Return(ty) = fn_sig.decl.output
1894+
&& let hir::TyKind::Path(qpath) = ty.kind
1895+
&& let hir::QPath::Resolved(None, path) = qpath
1896+
&& let Res::Def(DefKind::TyAlias, def_id) = path.res
1897+
{
1898+
// Do not suggest
1899+
// type T = dyn Trait;
1900+
// fn foo() -> impl T { .. }
1901+
err.span_note(self.tcx.def_span(def_id), "this type alias is unsized");
1902+
err.multipart_suggestion(
1903+
format!(
1904+
"consider boxing the return type, and wrapping all of the returned values in \
1905+
`Box::new`",
1906+
),
1907+
vec![
1908+
(ty.span.shrink_to_lo(), "Box<".to_string()),
1909+
(ty.span.shrink_to_hi(), ">".to_string()),
1910+
],
1911+
Applicability::MaybeIncorrect,
1912+
);
1913+
return false;
1914+
}
18891915

18901916
err.code(E0746);
18911917
err.primary_message("return type cannot be a trait object without pointer indirection");
18921918
err.children.clear();
18931919

1894-
let span = obligation.cause.span;
1920+
let mut span = obligation.cause.span;
1921+
if let DefKind::Closure = self.tcx.def_kind(obligation.cause.body_id)
1922+
&& let parent = self.tcx.parent(obligation.cause.body_id.into())
1923+
&& let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(parent)
1924+
&& self.tcx.asyncness(parent).is_async()
1925+
&& let Some(parent) = parent.as_local()
1926+
&& let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. })
1927+
| Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(fn_sig, _), .. })
1928+
| Node::TraitItem(hir::TraitItem {
1929+
kind: hir::TraitItemKind::Fn(fn_sig, _), ..
1930+
}) = self.tcx.hir_node_by_def_id(parent)
1931+
{
1932+
// Do not suggest (#147894)
1933+
// async fn foo() -> dyn Display impl { .. }
1934+
// and
1935+
// async fn foo() -> dyn Display Box<dyn { .. }>
1936+
span = fn_sig.decl.output.span();
1937+
err.span(span);
1938+
}
18951939
let body = self.tcx.hir_body_owned_by(obligation.cause.body_id);
18961940

18971941
let mut visitor = ReturnsVisitor::default();

src/tools/clippy/tests/ui/future_not_send.stderr

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: future cannot be sent between threads safely
2-
--> tests/ui/future_not_send.rs:8:1
2+
--> tests/ui/future_not_send.rs:8:62
33
|
44
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send`
5+
| ^^^^ future returned by `private_future` is not `Send`
66
|
77
note: future is not `Send` as this value is used across an await
88
--> tests/ui/future_not_send.rs:11:20
@@ -23,10 +23,10 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
2323
= help: to override `-D warnings` add `#[allow(clippy::future_not_send)]`
2424

2525
error: future cannot be sent between threads safely
26-
--> tests/ui/future_not_send.rs:14:1
26+
--> tests/ui/future_not_send.rs:14:41
2727
|
2828
LL | pub async fn public_future(rc: Rc<[u8]>) {
29-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send`
29+
| ^ future returned by `public_future` is not `Send`
3030
|
3131
note: future is not `Send` as this value is used across an await
3232
--> tests/ui/future_not_send.rs:17:20
@@ -39,10 +39,10 @@ LL | async { true }.await;
3939
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
4040

4141
error: future cannot be sent between threads safely
42-
--> tests/ui/future_not_send.rs:24:1
42+
--> tests/ui/future_not_send.rs:24:63
4343
|
4444
LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
45-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future2` is not `Send`
45+
| ^^^^ future returned by `private_future2` is not `Send`
4646
|
4747
note: captured value is not `Send`
4848
--> tests/ui/future_not_send.rs:24:26
@@ -58,10 +58,10 @@ LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
5858
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
5959

6060
error: future cannot be sent between threads safely
61-
--> tests/ui/future_not_send.rs:30:1
61+
--> tests/ui/future_not_send.rs:30:42
6262
|
6363
LL | pub async fn public_future2(rc: Rc<[u8]>) {}
64-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future2` is not `Send`
64+
| ^ future returned by `public_future2` is not `Send`
6565
|
6666
note: captured value is not `Send`
6767
--> tests/ui/future_not_send.rs:30:29
@@ -71,10 +71,10 @@ LL | pub async fn public_future2(rc: Rc<[u8]>) {}
7171
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
7272

7373
error: future cannot be sent between threads safely
74-
--> tests/ui/future_not_send.rs:42:5
74+
--> tests/ui/future_not_send.rs:42:39
7575
|
7676
LL | async fn private_future(&self) -> usize {
77-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send`
77+
| ^^^^^ future returned by `private_future` is not `Send`
7878
|
7979
note: future is not `Send` as this value is used across an await
8080
--> tests/ui/future_not_send.rs:45:24
@@ -87,10 +87,10 @@ LL | async { true }.await;
8787
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
8888

8989
error: future cannot be sent between threads safely
90-
--> tests/ui/future_not_send.rs:49:5
90+
--> tests/ui/future_not_send.rs:49:38
9191
|
9292
LL | pub async fn public_future(&self) {
93-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send`
93+
| ^ future returned by `public_future` is not `Send`
9494
|
9595
note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
9696
--> tests/ui/future_not_send.rs:49:32
@@ -100,13 +100,10 @@ LL | pub async fn public_future(&self) {
100100
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
101101

102102
error: future cannot be sent between threads safely
103-
--> tests/ui/future_not_send.rs:61:1
103+
--> tests/ui/future_not_send.rs:61:37
104104
|
105-
LL | / async fn generic_future<T>(t: T) -> T
106-
LL | |
107-
LL | | where
108-
LL | | T: Send,
109-
| |____________^ future returned by `generic_future` is not `Send`
105+
LL | async fn generic_future<T>(t: T) -> T
106+
| ^ future returned by `generic_future` is not `Send`
110107
|
111108
note: future is not `Send` as this value is used across an await
112109
--> tests/ui/future_not_send.rs:67:20
@@ -118,10 +115,10 @@ LL | async { true }.await;
118115
= note: `T` doesn't implement `std::marker::Sync`
119116

120117
error: future cannot be sent between threads safely
121-
--> tests/ui/future_not_send.rs:83:1
118+
--> tests/ui/future_not_send.rs:83:51
122119
|
123120
LL | async fn generic_future_always_unsend<T>(_: Rc<T>) {
124-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `generic_future_always_unsend` is not `Send`
121+
| ^ future returned by `generic_future_always_unsend` is not `Send`
125122
|
126123
note: future is not `Send` as this value is used across an await
127124
--> tests/ui/future_not_send.rs:86:20

tests/ui/async-await/async-await-let-else.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ error[E0277]: `Rc<()>` cannot be sent between threads safely
2222
--> $DIR/async-await-let-else.rs:47:13
2323
|
2424
LL | async fn foo2(x: Option<bool>) {
25-
| ------------------------------ within this `impl Future<Output = ()>`
25+
| - within this `impl Future<Output = ()>`
2626
...
2727
LL | is_send(foo2(Some(true)));
2828
| ------- ^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//@ edition:2024
2+
//@ run-rustfix
3+
4+
async fn f() -> Box<impl core::fmt::Debug> {
5+
//~^ ERROR return type cannot be a trait object without pointer indirection
6+
//~| HELP consider returning an `impl Trait` instead of a `dyn Trait`
7+
//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new`
8+
Box::new("")
9+
}
10+
trait T {
11+
async fn f(&self) -> Box<impl core::fmt::Debug> {
12+
//~^ ERROR return type cannot be a trait object without pointer indirection
13+
//~| HELP consider returning an `impl Trait` instead of a `dyn Trait`
14+
//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new`
15+
Box::new("")
16+
}
17+
}
18+
impl T for () {
19+
async fn f(&self) -> Box<impl core::fmt::Debug> {
20+
//~^ ERROR return type cannot be a trait object without pointer indirection
21+
//~| HELP consider returning an `impl Trait` instead of a `dyn Trait`
22+
//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new`
23+
Box::new("")
24+
}
25+
}
26+
27+
fn main() {
28+
let _ = f();
29+
let _ = ().f();
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//@ edition:2024
2+
//@ run-rustfix
3+
4+
async fn f() -> dyn core::fmt::Debug {
5+
//~^ ERROR return type cannot be a trait object without pointer indirection
6+
//~| HELP consider returning an `impl Trait` instead of a `dyn Trait`
7+
//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new`
8+
Box::new("")
9+
}
10+
trait T {
11+
async fn f(&self) -> dyn core::fmt::Debug {
12+
//~^ ERROR return type cannot be a trait object without pointer indirection
13+
//~| HELP consider returning an `impl Trait` instead of a `dyn Trait`
14+
//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new`
15+
Box::new("")
16+
}
17+
}
18+
impl T for () {
19+
async fn f(&self) -> dyn core::fmt::Debug {
20+
//~^ ERROR return type cannot be a trait object without pointer indirection
21+
//~| HELP consider returning an `impl Trait` instead of a `dyn Trait`
22+
//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new`
23+
Box::new("")
24+
}
25+
}
26+
27+
fn main() {
28+
let _ = f();
29+
let _ = ().f();
30+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
error[E0746]: return type cannot be a trait object without pointer indirection
2+
--> $DIR/dyn-in-return-type.rs:4:17
3+
|
4+
LL | async fn f() -> dyn core::fmt::Debug {
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
|
7+
help: consider returning an `impl Trait` instead of a `dyn Trait`
8+
|
9+
LL - async fn f() -> dyn core::fmt::Debug {
10+
LL + async fn f() -> impl core::fmt::Debug {
11+
|
12+
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
13+
|
14+
LL | async fn f() -> Box<dyn core::fmt::Debug> {
15+
| ++++ +
16+
17+
error[E0746]: return type cannot be a trait object without pointer indirection
18+
--> $DIR/dyn-in-return-type.rs:11:26
19+
|
20+
LL | async fn f(&self) -> dyn core::fmt::Debug {
21+
| ^^^^^^^^^^^^^^^^^^^^
22+
|
23+
help: consider returning an `impl Trait` instead of a `dyn Trait`
24+
|
25+
LL - async fn f(&self) -> dyn core::fmt::Debug {
26+
LL + async fn f(&self) -> impl core::fmt::Debug {
27+
|
28+
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
29+
|
30+
LL | async fn f(&self) -> Box<dyn core::fmt::Debug> {
31+
| ++++ +
32+
33+
error[E0746]: return type cannot be a trait object without pointer indirection
34+
--> $DIR/dyn-in-return-type.rs:19:26
35+
|
36+
LL | async fn f(&self) -> dyn core::fmt::Debug {
37+
| ^^^^^^^^^^^^^^^^^^^^
38+
|
39+
help: consider returning an `impl Trait` instead of a `dyn Trait`
40+
|
41+
LL - async fn f(&self) -> dyn core::fmt::Debug {
42+
LL + async fn f(&self) -> impl core::fmt::Debug {
43+
|
44+
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
45+
|
46+
LL | async fn f(&self) -> Box<dyn core::fmt::Debug> {
47+
| ++++ +
48+
49+
error: aborting due to 3 previous errors
50+
51+
For more information about this error, try `rustc --explain E0746`.

tests/ui/async-await/async-fn/recurse-ice-129215.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ LL | a()
77
= help: the trait `Future` is not implemented for `()`
88

99
error[E0277]: `()` is not a future
10-
--> $DIR/recurse-ice-129215.rs:3:1
10+
--> $DIR/recurse-ice-129215.rs:3:13
1111
|
1212
LL | async fn a() {
13-
| ^^^^^^^^^^^^ `()` is not a future
13+
| ^ `()` is not a future
1414
|
1515
= help: the trait `Future` is not implemented for `()`
1616

tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0053]: method `foo` has an incompatible type for trait
2-
--> $DIR/async-example-desugared-boxed-in-trait.rs:11:5
2+
--> $DIR/async-example-desugared-boxed-in-trait.rs:11:28
33
|
44
LL | async fn foo(&self) -> i32 {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future
5+
| ^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future
66
|
77
note: type in trait
88
--> $DIR/async-example-desugared-boxed-in-trait.rs:7:22

tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ warning: impl trait in impl method signature does not match trait method signatu
22
--> $DIR/async-example-desugared-boxed.rs:14:22
33
|
44
LL | async fn foo(&self) -> i32;
5-
| --------------------------- return type from trait method defined here
5+
| --- return type from trait method defined here
66
...
77
LL | fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>> {
88
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)