parent
19423b5944
commit
e477cf9475
4 changed files with 113 additions and 1 deletions
|
@ -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,
|
||||
|
|
16
tests/ui/type/type-check/coerce-result-return-value.fixed
Normal file
16
tests/ui/type/type-check/coerce-result-return-value.fixed
Normal 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(()));
|
||||
}
|
16
tests/ui/type/type-check/coerce-result-return-value.rs
Normal file
16
tests/ui/type/type-check/coerce-result-return-value.rs
Normal 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(()));
|
||||
}
|
33
tests/ui/type/type-check/coerce-result-return-value.stderr
Normal file
33
tests/ui/type/type-check/coerce-result-return-value.stderr
Normal 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`.
|
Loading…
Add table
Reference in a new issue