Skip to content

Commit ec2f087

Browse files
authored
Rollup merge of #91022 - compiler-errors:modulo_infer, r=estebank
Suggest `await` in more situations where infer types are involved Currently we use `TyS::same_type` in diagnostics that suggest adding `.await` to opaque future types. This change makes the suggestion slightly more general, when we're comparing types like `Result<T, E>` and `Result<_, _>` which happens sometimes in places like `match` patterns or `let` statements with partially-elaborated types. ---- Question: 1. Is this change worthwhile? Totally fine if it doesn't make sense adding. 2. Should `same_type_modulo_infer` live in `rustc_infer::infer::error_reporting` or alongside the other method in `rustc_middle::ty::util`? 3. Should we generalize this change? I wanted to change all usages, but I don't want erroneous suggestions when adding `.field_name`...
2 parents f37a6ca + 1f625b7 commit ec2f087

File tree

3 files changed

+85
-4
lines changed

3 files changed

+85
-4
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+31-3
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,34 @@ pub fn unexpected_hidden_region_diagnostic(
310310
err
311311
}
312312

313+
/// Structurally compares two types, modulo any inference variables.
314+
///
315+
/// Returns `true` if two types are equal, or if one type is an inference variable compatible
316+
/// with the other type. A TyVar inference type is compatible with any type, and an IntVar or
317+
/// FloatVar inference type are compatible with themselves or their concrete types (Int and
318+
/// Float types, respectively). When comparing two ADTs, these rules apply recursively.
319+
pub fn same_type_modulo_infer(a: Ty<'tcx>, b: Ty<'ctx>) -> bool {
320+
match (&a.kind(), &b.kind()) {
321+
(&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
322+
if did_a != did_b {
323+
return false;
324+
}
325+
326+
substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type_modulo_infer(a, b))
327+
}
328+
(&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_)))
329+
| (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_) | &ty::Infer(ty::InferTy::IntVar(_)))
330+
| (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
331+
| (
332+
&ty::Infer(ty::InferTy::FloatVar(_)),
333+
&ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)),
334+
)
335+
| (&ty::Infer(ty::InferTy::TyVar(_)), _)
336+
| (_, &ty::Infer(ty::InferTy::TyVar(_))) => true,
337+
_ => a == b,
338+
}
339+
}
340+
313341
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
314342
pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
315343
debug!("report_region_errors(): {} errors to start", errors.len());
@@ -1761,7 +1789,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17611789
self.get_impl_future_output_ty(exp_found.expected),
17621790
self.get_impl_future_output_ty(exp_found.found),
17631791
) {
1764-
(Some(exp), Some(found)) if ty::TyS::same_type(exp, found) => match &cause.code {
1792+
(Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match &cause.code {
17651793
ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
17661794
diag.multipart_suggestion(
17671795
"consider `await`ing on both `Future`s",
@@ -1793,15 +1821,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17931821
diag.help("consider `await`ing on both `Future`s");
17941822
}
17951823
},
1796-
(_, Some(ty)) if ty::TyS::same_type(exp_found.expected, ty) => {
1824+
(_, Some(ty)) if same_type_modulo_infer(exp_found.expected, ty) => {
17971825
diag.span_suggestion_verbose(
17981826
exp_span.shrink_to_hi(),
17991827
"consider `await`ing on the `Future`",
18001828
".await".to_string(),
18011829
Applicability::MaybeIncorrect,
18021830
);
18031831
}
1804-
(Some(ty), _) if ty::TyS::same_type(ty, exp_found.found) => match cause.code {
1832+
(Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code {
18051833
ObligationCauseCode::Pattern { span: Some(span), .. }
18061834
| ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => {
18071835
diag.span_suggestion_verbose(

src/test/ui/async-await/suggest-missing-await.rs

+17
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,21 @@ async fn suggest_await_on_match_expr() {
5454
};
5555
}
5656

57+
async fn dummy_result() -> Result<(), ()> {
58+
Ok(())
59+
}
60+
61+
#[allow(unused)]
62+
async fn suggest_await_in_generic_pattern() {
63+
match dummy_result() {
64+
//~^ HELP consider `await`ing on the `Future`
65+
//~| HELP consider `await`ing on the `Future`
66+
//~| SUGGESTION .await
67+
Ok(_) => {}
68+
//~^ ERROR mismatched types [E0308]
69+
Err(_) => {}
70+
//~^ ERROR mismatched types [E0308]
71+
}
72+
}
73+
5774
fn main() {}

src/test/ui/async-await/suggest-missing-await.stderr

+37-1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,42 @@ help: consider `await`ing on the `Future`
106106
LL | let _x = match dummy().await {
107107
| ++++++
108108

109-
error: aborting due to 5 previous errors
109+
error[E0308]: mismatched types
110+
--> $DIR/suggest-missing-await.rs:67:9
111+
|
112+
LL | Ok(_) => {}
113+
| ^^^^^ expected opaque type, found enum `Result`
114+
|
115+
note: while checking the return type of the `async fn`
116+
--> $DIR/suggest-missing-await.rs:57:28
117+
|
118+
LL | async fn dummy_result() -> Result<(), ()> {
119+
| ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
120+
= note: expected opaque type `impl Future<Output = Result<(), ()>>`
121+
found enum `Result<_, _>`
122+
help: consider `await`ing on the `Future`
123+
|
124+
LL | match dummy_result().await {
125+
| ++++++
126+
127+
error[E0308]: mismatched types
128+
--> $DIR/suggest-missing-await.rs:69:9
129+
|
130+
LL | Err(_) => {}
131+
| ^^^^^^ expected opaque type, found enum `Result`
132+
|
133+
note: while checking the return type of the `async fn`
134+
--> $DIR/suggest-missing-await.rs:57:28
135+
|
136+
LL | async fn dummy_result() -> Result<(), ()> {
137+
| ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
138+
= note: expected opaque type `impl Future<Output = Result<(), ()>>`
139+
found enum `Result<_, _>`
140+
help: consider `await`ing on the `Future`
141+
|
142+
LL | match dummy_result().await {
143+
| ++++++
144+
145+
error: aborting due to 7 previous errors
110146

111147
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)