Suggest coercion of Result using ?

Fix #47560.
This commit is contained in:
Esteban Küber 2023-01-08 02:54:59 +00:00
parent 19423b5944
commit e477cf9475
4 changed files with 113 additions and 1 deletions

View file

@ -45,7 +45,7 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Expr;
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult};
use rustc_infer::infer::{Coercion, InferOk, InferResult, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::{
@ -1565,6 +1565,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
&& let hir::ExprKind::Loop(loop_blk, ..) = expression.kind {
intravisit::walk_block(& mut visitor, loop_blk);
}
if let Some(expr) = expression {
self.note_result_coercion(fcx, &mut err, expr, expected, found);
}
}
ObligationCauseCode::ReturnValue(id) => {
err = self.report_return_mismatched_types(
@ -1581,6 +1584,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
let id = fcx.tcx.hir().parent_id(id);
unsized_return = self.is_return_ty_unsized(fcx, id);
}
if let Some(expr) = expression {
self.note_result_coercion(fcx, &mut err, expr, expected, found);
}
}
_ => {
err = fcx.err_ctxt().report_mismatched_types(
@ -1619,6 +1625,47 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
}
}
fn note_result_coercion(
&self,
fcx: &FnCtxt<'_, 'tcx>,
err: &mut Diagnostic,
expr: &hir::Expr<'tcx>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
) {
let ty::Adt(e, substs_e) = expected.kind() else { return; };
let ty::Adt(f, substs_f) = found.kind() else { return; };
if e.did() != f.did() {
return;
}
if Some(e.did()) != fcx.tcx.get_diagnostic_item(sym::Result) {
return;
}
let e = substs_e.type_at(1);
let f = substs_f.type_at(1);
if fcx
.tcx
.infer_ctxt()
.build()
.type_implements_trait(
fcx.tcx.get_diagnostic_item(sym::Into).unwrap(),
[fcx.tcx.erase_regions(f), fcx.tcx.erase_regions(e)],
fcx.param_env,
)
.must_apply_modulo_regions()
{
err.multipart_suggestion(
"you can rely on the implicit conversion that `?` does to transform the error type",
vec![
(expr.span.shrink_to_lo(), "Ok(".to_string()),
(expr.span.shrink_to_hi(), "?)".to_string()),
],
Applicability::MaybeIncorrect,
);
}
}
fn note_unreachable_loop_return(
&self,
err: &mut Diagnostic,

View file

@ -0,0 +1,16 @@
// run-rustfix
struct A;
struct B;
impl From<A> for B {
fn from(_: A) -> Self { B }
}
fn foo1(x: Result<(), A>) -> Result<(), B> {
Ok(x?) //~ ERROR mismatched types
}
fn foo2(x: Result<(), A>) -> Result<(), B> {
return Ok(x?); //~ ERROR mismatched types
}
fn main() {
let _ = foo1(Ok(()));
let _ = foo2(Ok(()));
}

View file

@ -0,0 +1,16 @@
// run-rustfix
struct A;
struct B;
impl From<A> for B {
fn from(_: A) -> Self { B }
}
fn foo1(x: Result<(), A>) -> Result<(), B> {
x //~ ERROR mismatched types
}
fn foo2(x: Result<(), A>) -> Result<(), B> {
return x; //~ ERROR mismatched types
}
fn main() {
let _ = foo1(Ok(()));
let _ = foo2(Ok(()));
}

View file

@ -0,0 +1,33 @@
error[E0308]: mismatched types
--> $DIR/coerce-result-return-value.rs:8:5
|
LL | fn foo1(x: Result<(), A>) -> Result<(), B> {
| ------------- expected `Result<(), B>` because of return type
LL | x
| ^ expected struct `B`, found struct `A`
|
= note: expected enum `Result<_, B>`
found enum `Result<_, A>`
help: you can rely on the implicit conversion that `?` does to transform the error type
|
LL | Ok(x?)
| +++ ++
error[E0308]: mismatched types
--> $DIR/coerce-result-return-value.rs:11:12
|
LL | fn foo2(x: Result<(), A>) -> Result<(), B> {
| ------------- expected `Result<(), B>` because of return type
LL | return x;
| ^ expected struct `B`, found struct `A`
|
= note: expected enum `Result<_, B>`
found enum `Result<_, A>`
help: you can rely on the implicit conversion that `?` does to transform the error type
|
LL | return Ok(x?);
| +++ ++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.