Skip to content

Commit f375177

Browse files
committed
Auto merge of #157177 - matthiaskrgr:rollup-ZLL6iEP, r=matthiaskrgr
Rollup of 2 pull requests Successful merges: - #157165 (Async return ty) - #157176 (Reorganize `tests/ui/issues` [2/N])
2 parents e7a21fa + d41954e commit f375177

17 files changed

Lines changed: 241 additions & 71 deletions

compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs

Lines changed: 81 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
22
use rustc_errors::{Diag, MultiSpan, pluralize};
3-
use rustc_hir as hir;
43
use rustc_hir::def::DefKind;
5-
use rustc_hir::find_attr;
4+
use rustc_hir::{self as hir, LangItem, find_attr};
65
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
76
use rustc_middle::ty::error::{ExpectedFound, TypeError};
87
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
@@ -140,62 +139,88 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
140139
let item_name = tcx.item_name(def_id);
141140
let item_args = self.format_generic_args(assoc_args);
142141

143-
// Here, we try to see if there's an existing
144-
// trait implementation that matches the one that
145-
// we're suggesting to restrict. If so, find the
146-
// "end", whether it be at the end of the trait
147-
// or the end of the generic arguments.
148-
let mut matching_span = None;
149-
let mut matched_end_of_args = false;
150-
for bound in generics.bounds_for_param(local_id) {
151-
let potential_spans = bound.bounds.iter().find_map(|bound| {
152-
let bound_trait_path = bound.trait_ref()?.path;
153-
let def_id = bound_trait_path.res.opt_def_id()?;
154-
let generic_args = bound_trait_path
155-
.segments
156-
.iter()
157-
.last()
158-
.map(|path| path.args());
159-
(def_id == trait_ref.def_id)
160-
.then_some((bound_trait_path.span, generic_args))
161-
});
162-
163-
if let Some((end_of_trait, end_of_args)) = potential_spans {
164-
let args_span = end_of_args.and_then(|args| args.span());
165-
matched_end_of_args = args_span.is_some();
166-
matching_span = args_span
167-
.or_else(|| Some(end_of_trait))
168-
.map(|span| span.shrink_to_hi());
169-
break;
170-
}
171-
}
142+
if
143+
// if we're referencing an async fn trait's output future
144+
//
145+
// AsyncFnOnce
146+
(tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncFnOnce)
147+
&& tcx.is_lang_item(def_id, LangItem::CallOnceFuture))
148+
// AsyncFnMut
149+
||
150+
(tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncFnMut)
151+
&& tcx.is_lang_item(def_id, LangItem::CallRefFuture))
152+
// AsyncFn
153+
||
154+
(tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncFn)
155+
&& tcx.is_lang_item(def_id, LangItem::CallRefFuture))
156+
{
157+
// don't make a suggestion to constrain it, it's not possible in
158+
// current rust. In fact, when something is referring to this, you
159+
// may have just needed to await something.
172160

173-
if matched_end_of_args {
174-
// Append suggestion to the end of our args
175-
let path = format!(", {item_name}{item_args} = {p}");
176-
note = !suggest_constraining_type_param(
177-
tcx,
178-
generics,
179-
diag,
180-
&proj.self_ty().to_string(),
181-
&path,
182-
None,
183-
matching_span,
184-
);
161+
diag.help("you may have forgotten to await an async function");
162+
diag.note(format!("it is currently not possible to add bounds constraining the future returned from an async function (`{item_name}`)"));
163+
// don't note, since it's talking about missing bounds. There's
164+
// currently no way to bound the return future
165+
note = false;
185166
} else {
186-
// Suggest adding a bound to an existing trait
187-
// or if the trait doesn't exist, add the trait
188-
// and the suggested bounds.
189-
let path = format!("<{item_name}{item_args} = {p}>");
190-
note = !suggest_constraining_type_param(
191-
tcx,
192-
generics,
193-
diag,
194-
&proj.self_ty().to_string(),
195-
&path,
196-
None,
197-
matching_span,
198-
);
167+
// Here, we try to see if there's an existing
168+
// trait implementation that matches the one that
169+
// we're suggesting to restrict. If so, find the
170+
// "end", whether it be at the end of the trait
171+
// or the end of the generic arguments.
172+
let mut matching_span = None;
173+
let mut matched_end_of_args = false;
174+
for bound in generics.bounds_for_param(local_id) {
175+
let potential_spans = bound.bounds.iter().find_map(|bound| {
176+
let bound_trait_path = bound.trait_ref()?.path;
177+
let def_id = bound_trait_path.res.opt_def_id()?;
178+
let generic_args = bound_trait_path
179+
.segments
180+
.iter()
181+
.last()
182+
.map(|path| path.args());
183+
(def_id == trait_ref.def_id)
184+
.then_some((bound_trait_path.span, generic_args))
185+
});
186+
187+
if let Some((end_of_trait, end_of_args)) = potential_spans {
188+
let args_span = end_of_args.and_then(|args| args.span());
189+
matched_end_of_args = args_span.is_some();
190+
matching_span = args_span
191+
.or_else(|| Some(end_of_trait))
192+
.map(|span| span.shrink_to_hi());
193+
break;
194+
}
195+
}
196+
197+
if matched_end_of_args {
198+
// Append suggestion to the end of our args
199+
let path = format!(", {item_name}{item_args} = {p}");
200+
note = !suggest_constraining_type_param(
201+
tcx,
202+
generics,
203+
diag,
204+
&proj.self_ty().to_string(),
205+
&path,
206+
None,
207+
matching_span,
208+
);
209+
} else {
210+
// Suggest adding a bound to an existing trait
211+
// or if the trait doesn't exist, add the trait
212+
// and the suggested bounds.
213+
let path = format!("<{item_name}{item_args} = {p}>");
214+
note = !suggest_constraining_type_param(
215+
tcx,
216+
generics,
217+
diag,
218+
&proj.self_ty().to_string(),
219+
&path,
220+
None,
221+
matching_span,
222+
);
223+
}
199224
}
200225
}
201226
if note {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//@ edition: 2024
2+
3+
async fn once<O, F: AsyncFnOnce() -> O>(f: F) -> O {
4+
Ok::<(), ()>(())?;
5+
//~^ ERROR: the `?` operator can only be used in an async function that returns
6+
7+
f()
8+
//~^ ERROR mismatched types
9+
}
10+
11+
async fn fnref<O, F: AsyncFn() -> O>(f: F) -> O {
12+
Ok::<(), ()>(())?;
13+
//~^ ERROR: the `?` operator can only be used in an async function that returns
14+
15+
f()
16+
//~^ ERROR mismatched types
17+
}
18+
19+
20+
async fn fnmut<O, F: AsyncFnMut() -> O>(f: F) -> O {
21+
Ok::<(), ()>(())?;
22+
//~^ ERROR: the `?` operator can only be used in an async function that returns
23+
24+
f()
25+
//~^ ERROR mismatched types
26+
}
27+
28+
fn main() {}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`)
2+
--> $DIR/wrong-suggestion-result.rs:4:21
3+
|
4+
LL | async fn once<O, F: AsyncFnOnce() -> O>(f: F) -> O {
5+
| ____________________________________________________-
6+
LL | | Ok::<(), ()>(())?;
7+
| | ^ cannot use the `?` operator in an async function that returns `O`
8+
... |
9+
LL | | }
10+
| |_- this function should return `Result` or `Option` to accept `?`
11+
|
12+
help: consider restricting type parameter `O` with unstable trait `FromResidual`
13+
|
14+
LL | async fn once<O: std::ops::FromResidual<std::result::Result<std::convert::Infallible, ()>>, F: AsyncFnOnce() -> O>(f: F) -> O {
15+
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16+
17+
error[E0308]: mismatched types
18+
--> $DIR/wrong-suggestion-result.rs:7:5
19+
|
20+
LL | async fn once<O, F: AsyncFnOnce() -> O>(f: F) -> O {
21+
| - expected this type parameter - expected `O` because of return type
22+
...
23+
LL | f()
24+
| ^^^ expected type parameter `O`, found associated type
25+
|
26+
= note: expected type parameter `O`
27+
found associated type `<F as AsyncFnOnce<()>>::CallOnceFuture`
28+
= help: you may have forgotten to await an async function
29+
= note: it is currently not possible to add bounds constraining the future returned from an async function (`CallOnceFuture`)
30+
31+
error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`)
32+
--> $DIR/wrong-suggestion-result.rs:12:21
33+
|
34+
LL | async fn fnref<O, F: AsyncFn() -> O>(f: F) -> O {
35+
| _________________________________________________-
36+
LL | | Ok::<(), ()>(())?;
37+
| | ^ cannot use the `?` operator in an async function that returns `O`
38+
... |
39+
LL | | }
40+
| |_- this function should return `Result` or `Option` to accept `?`
41+
|
42+
help: consider restricting type parameter `O` with unstable trait `FromResidual`
43+
|
44+
LL | async fn fnref<O: std::ops::FromResidual<std::result::Result<std::convert::Infallible, ()>>, F: AsyncFn() -> O>(f: F) -> O {
45+
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
46+
47+
error[E0308]: mismatched types
48+
--> $DIR/wrong-suggestion-result.rs:15:5
49+
|
50+
LL | async fn fnref<O, F: AsyncFn() -> O>(f: F) -> O {
51+
| - expected this type parameter - expected `O` because of return type
52+
...
53+
LL | f()
54+
| ^^^ expected type parameter `O`, found associated type
55+
|
56+
= note: expected type parameter `O`
57+
found associated type `<F as AsyncFnMut<()>>::CallRefFuture<'_>`
58+
= help: you may have forgotten to await an async function
59+
= note: it is currently not possible to add bounds constraining the future returned from an async function (`CallRefFuture`)
60+
61+
error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`)
62+
--> $DIR/wrong-suggestion-result.rs:21:21
63+
|
64+
LL | async fn fnmut<O, F: AsyncFnMut() -> O>(f: F) -> O {
65+
| ____________________________________________________-
66+
LL | | Ok::<(), ()>(())?;
67+
| | ^ cannot use the `?` operator in an async function that returns `O`
68+
... |
69+
LL | | }
70+
| |_- this function should return `Result` or `Option` to accept `?`
71+
|
72+
help: consider restricting type parameter `O` with unstable trait `FromResidual`
73+
|
74+
LL | async fn fnmut<O: std::ops::FromResidual<std::result::Result<std::convert::Infallible, ()>>, F: AsyncFnMut() -> O>(f: F) -> O {
75+
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
76+
77+
error[E0308]: mismatched types
78+
--> $DIR/wrong-suggestion-result.rs:24:5
79+
|
80+
LL | async fn fnmut<O, F: AsyncFnMut() -> O>(f: F) -> O {
81+
| - expected this type parameter - expected `O` because of return type
82+
...
83+
LL | f()
84+
| ^^^ expected type parameter `O`, found associated type
85+
|
86+
= note: expected type parameter `O`
87+
found associated type `<F as AsyncFnMut<()>>::CallRefFuture<'_>`
88+
= help: you may have forgotten to await an async function
89+
= note: it is currently not possible to add bounds constraining the future returned from an async function (`CallRefFuture`)
90+
91+
error: aborting due to 6 previous errors
92+
93+
Some errors have detailed explanations: E0277, E0308.
94+
For more information about an error, try `rustc --explain E0277`.

tests/ui/issues/issue-17746.rs renamed to tests/ui/autoref-autoderef/reborrow-mut-self-to-ref-self-method.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
//! Regression test for <https://github.com/rust-lang/rust/issues/17746>.
2+
13
//@ check-pass
24
#![allow(dead_code)]
3-
// Regression test for #17746
45

56
fn main() {}
67

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Regression test for <https://github.com/rust-lang/rust/issues/17322>.
2+
13
//@ run-pass
24

35
use std::io::{self, Write};

tests/ui/issues/auxiliary/issue-16643.rs renamed to tests/ui/cross-crate/auxiliary/for-loop-in-match-on-self.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Auxiliary crate for <https://github.com/rust-lang/rust/issues/16643>.
2+
13
#![crate_type = "lib"]
24

35
pub struct TreeBuilder<H> { pub h: H }
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//! Regression test for <https://github.com/rust-lang/rust/issues/16643>.
2+
//! Tests that method which matches on self with for loop doesn't ICE cross-crate.
3+
4+
//@ run-pass
5+
//@ aux-build:for-loop-in-match-on-self.rs
6+
7+
8+
extern crate for_loop_in_match_on_self as i;
9+
10+
pub fn main() {
11+
i::TreeBuilder { h: 3 }.process_token();
12+
}

tests/ui/issues/issue-16530.rs renamed to tests/ui/derives/derive-hash-on-unit-struct.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//! Regression test for <https://github.com/rust-lang/rust/issues/16530>.
2+
//! Tests that unit struct produce same constant hash instead of ICE'ing.
3+
14
//@ run-pass
25
#![allow(deprecated)]
36

tests/ui/issues/issue-17771.rs renamed to tests/ui/dst/reborrow-mut-dyn-trait-field.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//! Regression test for <https://github.com/rust-lang/rust/issues/17771>.
2+
//! Tests that borrowing mut dyn trait field in a method doesn't cause ICE.
3+
14
//@ run-pass
25
#![allow(dead_code)]
36

tests/ui/issues/issue-16643.rs

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)