mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-20 02:43:45 +00:00
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`...
This commit is contained in:
commit
ec2f087c47
@ -310,6 +310,34 @@ pub fn unexpected_hidden_region_diagnostic(
|
|||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Structurally compares two types, modulo any inference variables.
|
||||||
|
///
|
||||||
|
/// Returns `true` if two types are equal, or if one type is an inference variable compatible
|
||||||
|
/// with the other type. A TyVar inference type is compatible with any type, and an IntVar or
|
||||||
|
/// FloatVar inference type are compatible with themselves or their concrete types (Int and
|
||||||
|
/// Float types, respectively). When comparing two ADTs, these rules apply recursively.
|
||||||
|
pub fn same_type_modulo_infer(a: Ty<'tcx>, b: Ty<'ctx>) -> bool {
|
||||||
|
match (&a.kind(), &b.kind()) {
|
||||||
|
(&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
|
||||||
|
if did_a != did_b {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type_modulo_infer(a, b))
|
||||||
|
}
|
||||||
|
(&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_)))
|
||||||
|
| (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_) | &ty::Infer(ty::InferTy::IntVar(_)))
|
||||||
|
| (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
|
||||||
|
| (
|
||||||
|
&ty::Infer(ty::InferTy::FloatVar(_)),
|
||||||
|
&ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)),
|
||||||
|
)
|
||||||
|
| (&ty::Infer(ty::InferTy::TyVar(_)), _)
|
||||||
|
| (_, &ty::Infer(ty::InferTy::TyVar(_))) => true,
|
||||||
|
_ => a == b,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
|
pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
|
||||||
debug!("report_region_errors(): {} errors to start", errors.len());
|
debug!("report_region_errors(): {} errors to start", errors.len());
|
||||||
@ -1761,7 +1789,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
self.get_impl_future_output_ty(exp_found.expected),
|
self.get_impl_future_output_ty(exp_found.expected),
|
||||||
self.get_impl_future_output_ty(exp_found.found),
|
self.get_impl_future_output_ty(exp_found.found),
|
||||||
) {
|
) {
|
||||||
(Some(exp), Some(found)) if ty::TyS::same_type(exp, found) => match &cause.code {
|
(Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match &cause.code {
|
||||||
ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
|
ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
|
||||||
diag.multipart_suggestion(
|
diag.multipart_suggestion(
|
||||||
"consider `await`ing on both `Future`s",
|
"consider `await`ing on both `Future`s",
|
||||||
@ -1793,7 +1821,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
diag.help("consider `await`ing on both `Future`s");
|
diag.help("consider `await`ing on both `Future`s");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(_, Some(ty)) if ty::TyS::same_type(exp_found.expected, ty) => {
|
(_, Some(ty)) if same_type_modulo_infer(exp_found.expected, ty) => {
|
||||||
diag.span_suggestion_verbose(
|
diag.span_suggestion_verbose(
|
||||||
exp_span.shrink_to_hi(),
|
exp_span.shrink_to_hi(),
|
||||||
"consider `await`ing on the `Future`",
|
"consider `await`ing on the `Future`",
|
||||||
@ -1801,7 +1829,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
(Some(ty), _) if ty::TyS::same_type(ty, exp_found.found) => match cause.code {
|
(Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code {
|
||||||
ObligationCauseCode::Pattern { span: Some(span), .. }
|
ObligationCauseCode::Pattern { span: Some(span), .. }
|
||||||
| ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => {
|
| ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => {
|
||||||
diag.span_suggestion_verbose(
|
diag.span_suggestion_verbose(
|
||||||
|
@ -54,4 +54,21 @@ async fn suggest_await_on_match_expr() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn dummy_result() -> Result<(), ()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
async fn suggest_await_in_generic_pattern() {
|
||||||
|
match dummy_result() {
|
||||||
|
//~^ HELP consider `await`ing on the `Future`
|
||||||
|
//~| HELP consider `await`ing on the `Future`
|
||||||
|
//~| SUGGESTION .await
|
||||||
|
Ok(_) => {}
|
||||||
|
//~^ ERROR mismatched types [E0308]
|
||||||
|
Err(_) => {}
|
||||||
|
//~^ ERROR mismatched types [E0308]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -106,6 +106,42 @@ help: consider `await`ing on the `Future`
|
|||||||
LL | let _x = match dummy().await {
|
LL | let _x = match dummy().await {
|
||||||
| ++++++
|
| ++++++
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/suggest-missing-await.rs:67:9
|
||||||
|
|
|
||||||
|
LL | Ok(_) => {}
|
||||||
|
| ^^^^^ expected opaque type, found enum `Result`
|
||||||
|
|
|
||||||
|
note: while checking the return type of the `async fn`
|
||||||
|
--> $DIR/suggest-missing-await.rs:57:28
|
||||||
|
|
|
||||||
|
LL | async fn dummy_result() -> Result<(), ()> {
|
||||||
|
| ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
|
||||||
|
= note: expected opaque type `impl Future<Output = Result<(), ()>>`
|
||||||
|
found enum `Result<_, _>`
|
||||||
|
help: consider `await`ing on the `Future`
|
||||||
|
|
|
||||||
|
LL | match dummy_result().await {
|
||||||
|
| ++++++
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/suggest-missing-await.rs:69:9
|
||||||
|
|
|
||||||
|
LL | Err(_) => {}
|
||||||
|
| ^^^^^^ expected opaque type, found enum `Result`
|
||||||
|
|
|
||||||
|
note: while checking the return type of the `async fn`
|
||||||
|
--> $DIR/suggest-missing-await.rs:57:28
|
||||||
|
|
|
||||||
|
LL | async fn dummy_result() -> Result<(), ()> {
|
||||||
|
| ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
|
||||||
|
= note: expected opaque type `impl Future<Output = Result<(), ()>>`
|
||||||
|
found enum `Result<_, _>`
|
||||||
|
help: consider `await`ing on the `Future`
|
||||||
|
|
|
||||||
|
LL | match dummy_result().await {
|
||||||
|
| ++++++
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
Loading…
Reference in New Issue
Block a user