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::{
&& 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(
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(
}
}
}
+
+ 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,
--- /dev/null
+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`.